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 GuestView = require('binding').Binding.create('guestview').generate(); | |
11 var IdGenerator = requireNative('id_generator'); | 12 var IdGenerator = requireNative('id_generator'); |
12 var MessagingNatives = requireNative('messaging_natives'); | 13 var MessagingNatives = requireNative('messaging_natives'); |
13 var WebRequestEvent = require('webRequestInternal').WebRequestEvent; | 14 var WebRequestEvent = require('webRequestInternal').WebRequestEvent; |
14 var WebRequestSchema = | 15 var WebRequestSchema = |
15 requireNative('schema_registry').GetSchema('webRequest'); | 16 requireNative('schema_registry').GetSchema('webRequest'); |
16 var DeclarativeWebRequestSchema = | 17 var DeclarativeWebRequestSchema = |
17 requireNative('schema_registry').GetSchema('declarativeWebRequest'); | 18 requireNative('schema_registry').GetSchema('declarativeWebRequest'); |
18 var WebView = require('webview').WebView; | 19 var WebView = require('webview').WebView; |
19 | 20 |
20 var WEB_VIEW_ATTRIBUTE_MAXHEIGHT = 'maxheight'; | 21 var WEB_VIEW_ATTRIBUTE_MAXHEIGHT = 'maxheight'; |
21 var WEB_VIEW_ATTRIBUTE_MAXWIDTH = 'maxwidth'; | 22 var WEB_VIEW_ATTRIBUTE_MAXWIDTH = 'maxwidth'; |
22 var WEB_VIEW_ATTRIBUTE_MINHEIGHT = 'minheight'; | 23 var WEB_VIEW_ATTRIBUTE_MINHEIGHT = 'minheight'; |
23 var WEB_VIEW_ATTRIBUTE_MINWIDTH = 'minwidth'; | 24 var WEB_VIEW_ATTRIBUTE_MINWIDTH = 'minwidth'; |
25 var WEB_VIEW_ATTRIBUTE_PARTITION = 'partition'; | |
26 | |
27 var ERROR_MSG_ALREADY_NAVIGATED = | |
28 'The object has already navigated, so its partition cannot be changed.'; | |
29 var ERROR_MSG_INVALID_PARTITION_ATTRIBUTE = | |
30 'Invalid partition attribute.'; | |
31 | |
32 var LOG = function(msg) { | |
33 window.console.log(msg); | |
34 }; | |
24 | 35 |
25 /** @type {Array.<string>} */ | 36 /** @type {Array.<string>} */ |
26 var WEB_VIEW_ATTRIBUTES = [ | 37 var WEB_VIEW_ATTRIBUTES = [ |
27 'allowtransparency', | 38 'allowtransparency', |
28 'autosize', | 39 'autosize', |
29 'partition', | |
30 WEB_VIEW_ATTRIBUTE_MINHEIGHT, | 40 WEB_VIEW_ATTRIBUTE_MINHEIGHT, |
31 WEB_VIEW_ATTRIBUTE_MINWIDTH, | 41 WEB_VIEW_ATTRIBUTE_MINWIDTH, |
32 WEB_VIEW_ATTRIBUTE_MAXHEIGHT, | 42 WEB_VIEW_ATTRIBUTE_MAXHEIGHT, |
33 WEB_VIEW_ATTRIBUTE_MAXWIDTH | 43 WEB_VIEW_ATTRIBUTE_MAXWIDTH |
34 ]; | 44 ]; |
35 | 45 |
46 /** @class representing state of storage partition. */ | |
47 function Partition() { | |
48 this.validPartitionId_ = true; | |
49 this.persist_storage_ = false; | |
50 this.storage_partition_id_ = ''; | |
51 }; | |
52 | |
53 Partition.prototype.toAttribute = function() { | |
54 LOG('Partition.toAttribute'); | |
55 if (!this.validPartitionId_) { | |
56 LOG('Warning we have invalid partition id'); | |
57 return ''; | |
58 } | |
59 return (this.persist_storage_ ? 'persist:' : '') + this.storage_partition_id_; | |
60 }; | |
61 | |
62 Partition.prototype.fromAttribute = function(value, hasNavigated) { | |
63 LOG('Partition.fromAttribute'); | |
64 LOG('value: ' + value + ', hasNavigated: ' + hasNavigated); | |
65 var result = {}; | |
66 if (hasNavigated) { | |
67 result.error = ERROR_MSG_ALREADY_NAVIGATED; | |
68 return result; | |
69 } | |
70 if (!value) { | |
71 LOG('Partition.fromAttribute got empty value'); | |
72 value = ''; | |
73 } | |
74 | |
75 var LEN = 'persist:'.length; | |
76 if (value.substr(0, LEN) == 'persist:') { | |
77 value = value.substr(LEN); | |
78 if (!value) { | |
79 this.validPartitionId_ = false; | |
80 result.error = ERROR_MSG_INVALID_PARTITION_ATTRIBUTE; | |
81 return result; | |
82 } | |
83 this.persist_storage_ = true; | |
84 } else { | |
85 this.persist_storage_ = false; | |
86 } | |
87 | |
88 this.storage_partition_id_ = value; | |
89 return result; | |
90 }; | |
91 | |
36 var CreateEvent = function(name) { | 92 var CreateEvent = function(name) { |
37 var eventOpts = {supportsListeners: true, supportsFilters: true}; | 93 var eventOpts = {supportsListeners: true, supportsFilters: true}; |
38 return new EventBindings.Event(name, undefined, eventOpts); | 94 return new EventBindings.Event(name, undefined, eventOpts); |
39 }; | 95 }; |
40 | 96 |
41 // WEB_VIEW_EVENTS is a map of stable <webview> DOM event names to their | 97 // WEB_VIEW_EVENTS is a map of stable <webview> DOM event names to their |
42 // associated extension event descriptor objects. | 98 // associated extension event descriptor objects. |
43 // An event listener will be attached to the extension event |evt| specified in | 99 // An event listener will be attached to the extension event |evt| specified in |
44 // the descriptor. | 100 // the descriptor. |
45 // |fields| specifies the public-facing fields in the DOM event that are | 101 // |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 } | 222 } |
167 }; | 223 }; |
168 | 224 |
169 // Implemented when the experimental API is available. | 225 // Implemented when the experimental API is available. |
170 WebViewInternal.maybeRegisterExperimentalAPIs = function(proto) {} | 226 WebViewInternal.maybeRegisterExperimentalAPIs = function(proto) {} |
171 | 227 |
172 /** | 228 /** |
173 * @constructor | 229 * @constructor |
174 */ | 230 */ |
175 function WebViewInternal(webviewNode) { | 231 function WebViewInternal(webviewNode) { |
232 LOG('WebViewInternal.constructor'); | |
176 privates(webviewNode).internal = this; | 233 privates(webviewNode).internal = this; |
177 this.webviewNode = webviewNode; | 234 this.webviewNode = webviewNode; |
178 this.attached = false; | 235 this.attached = false; |
236 | |
237 this.beforeFirstNavigation_ = true; | |
Fady Samuel
2014/05/29 20:35:23
We haven't been using _ for privates now. Let's dr
lazyboy
2014/05/30 05:48:21
Ya, underscores are supposed to be for privates ac
| |
238 this.validPartitionId_ = true; | |
239 | |
179 this.browserPluginNode = this.createBrowserPluginNode(); | 240 this.browserPluginNode = this.createBrowserPluginNode(); |
180 var shadowRoot = this.webviewNode.createShadowRoot(); | 241 var shadowRoot = this.webviewNode.createShadowRoot(); |
181 shadowRoot.appendChild(this.browserPluginNode); | 242 shadowRoot.appendChild(this.browserPluginNode); |
182 | 243 |
183 this.setupWebviewNodeAttributes(); | 244 this.setupWebviewNodeAttributes(); |
184 this.setupFocusPropagation(); | 245 this.setupFocusPropagation(); |
185 this.setupWebviewNodeProperties(); | 246 this.setupWebviewNodeProperties(); |
247 | |
248 this.viewInstanceId = IdGenerator.GetNextId(); | |
249 | |
250 //this.allocateInstanceId(); | |
251 this.partition_ = new Partition(); | |
252 this.parseAttributes(); | |
253 | |
186 this.setupWebviewNodeEvents(); | 254 this.setupWebviewNodeEvents(); |
187 } | 255 } |
188 | 256 |
189 /** | 257 /** |
190 * @private | 258 * @private |
191 */ | 259 */ |
192 WebViewInternal.prototype.createBrowserPluginNode = function() { | 260 WebViewInternal.prototype.createBrowserPluginNode = function() { |
193 // We create BrowserPlugin as a custom element in order to observe changes | 261 // We create BrowserPlugin as a custom element in order to observe changes |
194 // to attributes synchronously. | 262 // to attributes synchronously. |
195 var browserPluginNode = new WebViewInternal.BrowserPlugin(); | 263 var browserPluginNode = new WebViewInternal.BrowserPlugin(); |
196 privates(browserPluginNode).internal = this; | 264 privates(browserPluginNode).internal = this; |
197 | 265 |
198 var ALL_ATTRIBUTES = WEB_VIEW_ATTRIBUTES.concat(['src']); | 266 $Array.forEach(WEB_VIEW_ATTRIBUTES, function(attributeName) { |
199 $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). |
209 // So copy from property if copying from attribute fails. | 276 // So copy from property if copying from attribute fails. |
(...skipping 182 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 GuestView.allocateInstanceId( | |
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 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
838 validateCall(); | 1016 validateCall(); |
839 if (!webview || !webview.tagName || webview.tagName != 'WEBVIEW') | 1017 if (!webview || !webview.tagName || webview.tagName != 'WEBVIEW') |
840 throw new Error(ERROR_MSG_WEBVIEW_EXPECTED); | 1018 throw new Error(ERROR_MSG_WEBVIEW_EXPECTED); |
841 // Attach happens asynchronously to give the tagWatcher an opportunity | 1019 // Attach happens asynchronously to give the tagWatcher an opportunity |
842 // to pick up the new webview before attach operates on it, if it hasn't | 1020 // to pick up the new webview before attach operates on it, if it hasn't |
843 // been attached to the DOM already. | 1021 // been attached to the DOM already. |
844 // Note: Any subsequent errors cannot be exceptions because they happen | 1022 // Note: Any subsequent errors cannot be exceptions because they happen |
845 // asynchronously. | 1023 // asynchronously. |
846 setTimeout(function() { | 1024 setTimeout(function() { |
847 var webViewInternal = privates(webview).internal; | 1025 var webViewInternal = privates(webview).internal; |
1026 LOG('=== Attach w/o a src'); | |
1027 | |
1028 if (event.storagePartitionId) { | |
1029 LOG('read partition string: ' + event.storagePartitionId); | |
1030 webViewInternal.webviewNode.setAttribute( | |
1031 'partition', event.storagePartitionId); | |
1032 var partition = new Partition(); | |
1033 partition.fromAttribute(event.storagePartitionId, | |
1034 webViewInternal.hasNavigated()); | |
1035 webViewInternal.partition_ = partition; | |
1036 } | |
1037 | |
848 var attached = | 1038 var attached = |
849 webViewInternal.attachWindowAndSetUpEvents(event.windowId); | 1039 webViewInternal.attachWindowAndSetUpEvents( |
1040 event.windowId, undefined, event.storagePartitionId); | |
850 | 1041 |
851 if (!attached) { | 1042 if (!attached) { |
852 window.console.error(ERROR_MSG_NEWWINDOW_UNABLE_TO_ATTACH); | 1043 window.console.error(ERROR_MSG_NEWWINDOW_UNABLE_TO_ATTACH); |
853 } | 1044 } |
854 // If the object being passed into attach is not a valid <webview> | 1045 // If the object being passed into attach is not a valid <webview> |
855 // then we will fail and it will be treated as if the new window | 1046 // then we will fail and it will be treated as if the new window |
856 // was rejected. The permission API plumbing is used here to clean | 1047 // was rejected. The permission API plumbing is used here to clean |
857 // up the state created for the new window if attaching fails. | 1048 // up the state created for the new window if attaching fails. |
858 WebView.setPermission( | 1049 WebView.setPermission( |
859 self.instanceId, requestId, attached ? 'allow' : 'deny'); | 1050 self.instanceId, requestId, attached ? 'allow' : 'deny'); |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1050 this.userAgentOverride = userAgentOverride; | 1241 this.userAgentOverride = userAgentOverride; |
1051 if (!this.instanceId) { | 1242 if (!this.instanceId) { |
1052 // If we are not attached yet, then we will pick up the user agent on | 1243 // If we are not attached yet, then we will pick up the user agent on |
1053 // attachment. | 1244 // attachment. |
1054 return; | 1245 return; |
1055 } | 1246 } |
1056 WebView.overrideUserAgent(this.instanceId, userAgentOverride); | 1247 WebView.overrideUserAgent(this.instanceId, userAgentOverride); |
1057 }; | 1248 }; |
1058 | 1249 |
1059 /** @private */ | 1250 /** @private */ |
1060 WebViewInternal.prototype.attachWindowAndSetUpEvents = function(instanceId) { | 1251 WebViewInternal.prototype.attachWindowAndSetUpEvents = function( |
1252 instanceId, opt_src, opt_partitionId) { | |
1061 this.instanceId = instanceId; | 1253 this.instanceId = instanceId; |
1254 // If we have a partition from the opener, use that instead. | |
1255 var storagePartitionId = | |
1256 opt_partitionId || | |
1257 this.webviewNode.getAttribute(WEB_VIEW_ATTRIBUTE_PARTITION) || | |
1258 this.webviewNode[WEB_VIEW_ATTRIBUTE_PARTITION]; | |
1062 var params = { | 1259 var params = { |
1063 'api': 'webview', | 1260 'api': 'webview', |
1064 'instanceId': this.viewInstanceId, | 1261 'instanceId': this.viewInstanceId, |
1065 'name': this.name | 1262 'name': this.name, |
1263 'src': opt_src, | |
1264 'storagePartitionId': storagePartitionId, | |
1265 'userAgentOverride': this.userAgentOverride | |
1066 }; | 1266 }; |
1067 if (this.userAgentOverride) { | |
1068 params['userAgentOverride'] = this.userAgentOverride; | |
1069 } | |
1070 this.setupNameAttribute(); | 1267 this.setupNameAttribute(); |
1071 var events = this.getEvents(); | 1268 var events = this.getEvents(); |
1072 for (var eventName in events) { | 1269 for (var eventName in events) { |
1073 this.setupEvent(eventName, events[eventName]); | 1270 this.setupEvent(eventName, events[eventName]); |
1074 } | 1271 } |
1075 | 1272 |
1076 return this.browserPluginNode['-internal-attach'](this.instanceId, params); | 1273 return this.browserPluginNode['-internal-attach'](this.instanceId, params); |
1077 }; | 1274 }; |
1078 | 1275 |
1079 // Registers browser plugin <object> custom element. | 1276 // Registers browser plugin <object> custom element. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1111 } | 1308 } |
1112 | 1309 |
1113 // Registers <webview> custom element. | 1310 // Registers <webview> custom element. |
1114 function registerWebViewElement() { | 1311 function registerWebViewElement() { |
1115 var proto = Object.create(HTMLElement.prototype); | 1312 var proto = Object.create(HTMLElement.prototype); |
1116 | 1313 |
1117 proto.createdCallback = function() { | 1314 proto.createdCallback = function() { |
1118 new WebViewInternal(this); | 1315 new WebViewInternal(this); |
1119 }; | 1316 }; |
1120 | 1317 |
1318 proto.customElementDetached = false; | |
1319 | |
1121 proto.attributeChangedCallback = function(name, oldValue, newValue) { | 1320 proto.attributeChangedCallback = function(name, oldValue, newValue) { |
1122 var internal = privates(this).internal; | 1321 var internal = privates(this).internal; |
1123 if (!internal) { | 1322 if (!internal) { |
1124 return; | 1323 return; |
1125 } | 1324 } |
1126 internal.handleWebviewAttributeMutation(name, oldValue, newValue); | 1325 internal.handleWebviewAttributeMutation(name, oldValue, newValue); |
1127 }; | 1326 }; |
1128 | 1327 |
1328 proto.detachedCallback = function() { | |
1329 LOG('<webview> got detached'); | |
1330 LOG('this.customElementDetached was: ' + this.customElementDetached); | |
1331 this.customElementDetached = true; | |
1332 }; | |
1333 proto.attachedCallback = function() { | |
1334 LOG('attached, for the first time or subsequent, must init later'); | |
1335 LOG('this.customElementDetached was: ' + this.customElementDetached); | |
1336 if (this.customElementDetached) { | |
1337 var otherThis = privates(this).internal; | |
1338 LOG('allocateInstanceId again'); | |
1339 otherThis.instanceId = undefined; | |
1340 otherThis.beforeFirstNavigation_ = true; | |
1341 otherThis.validPartitionId_ = true; | |
1342 otherThis.partition_.validPartitionId_ = true; | |
1343 | |
1344 otherThis.allocateInstanceId(); | |
1345 } | |
1346 this.customElementDetached = false; | |
1347 }; | |
1348 | |
1129 proto.back = function() { | 1349 proto.back = function() { |
1130 this.go(-1); | 1350 this.go(-1); |
1131 }; | 1351 }; |
1132 | 1352 |
1133 proto.forward = function() { | 1353 proto.forward = function() { |
1134 this.go(1); | 1354 this.go(1); |
1135 }; | 1355 }; |
1136 | 1356 |
1137 proto.canGoBack = function() { | 1357 proto.canGoBack = function() { |
1138 return privates(this).internal.canGoBack(); | 1358 return privates(this).internal.canGoBack(); |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1248 | 1468 |
1249 /** | 1469 /** |
1250 * Implemented when the experimental API is available. | 1470 * Implemented when the experimental API is available. |
1251 * @private | 1471 * @private |
1252 */ | 1472 */ |
1253 WebViewInternal.prototype.setupExperimentalContextMenus_ = function() {}; | 1473 WebViewInternal.prototype.setupExperimentalContextMenus_ = function() {}; |
1254 | 1474 |
1255 exports.WebView = WebView; | 1475 exports.WebView = WebView; |
1256 exports.WebViewInternal = WebViewInternal; | 1476 exports.WebViewInternal = WebViewInternal; |
1257 exports.CreateEvent = CreateEvent; | 1477 exports.CreateEvent = CreateEvent; |
OLD | NEW |