OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 the shared functionality for different guestview | 5 // This module implements the shared functionality for different guestview |
6 // containers, such as web_view, app_view, etc. | 6 // containers, such as web_view, app_view, etc. |
7 | 7 |
8 var DocumentNatives = requireNative('document_natives'); | 8 var DocumentNatives = requireNative('document_natives'); |
9 var GuestView = require('guestView').GuestView; | 9 var GuestView = require('guestView').GuestView; |
10 var GuestViewInternalNatives = requireNative('guest_view_internal'); | 10 var GuestViewInternalNatives = requireNative('guest_view_internal'); |
11 var IdGenerator = requireNative('id_generator'); | 11 var IdGenerator = requireNative('id_generator'); |
12 | 12 |
13 function GuestViewContainer(element, viewType) { | 13 function GuestViewContainer(element, viewType) { |
14 privates(element).internal = this; | 14 privates(element).internal = this; |
15 this.attributes = {}; | 15 this.attributes = {}; |
16 this.element = element; | 16 this.element = element; |
17 this.elementAttached = false; | 17 this.elementAttached = false; |
18 this.viewInstanceId = IdGenerator.GetNextId(); | 18 this.viewInstanceId = IdGenerator.GetNextId(); |
19 this.viewType = viewType; | 19 this.viewType = viewType; |
20 | 20 |
21 this.setupGuestProperty(); | 21 this.setupGuestProperty(); |
22 this.guest = new GuestView(viewType); | 22 this.guest = new GuestView(viewType); |
23 this.setupAttributes(); | 23 this.setupAttributes(); |
24 | 24 |
25 privates(this).browserPluginElement = this.createBrowserPluginElement(); | 25 privates(this).internalElement = this.createInternalElement$(); |
26 this.setupFocusPropagation(); | 26 this.setupFocusPropagation(); |
27 var shadowRoot = this.element.createShadowRoot(); | 27 var shadowRoot = this.element.createShadowRoot(); |
28 shadowRoot.appendChild(privates(this).browserPluginElement); | 28 shadowRoot.appendChild(privates(this).internalElement); |
29 | 29 |
30 GuestViewInternalNatives.RegisterView(this.viewInstanceId, this); | 30 GuestViewInternalNatives.RegisterView(this.viewInstanceId, this); |
31 } | 31 } |
32 | 32 |
33 // Forward public API methods from |proto| to their internal implementations. | 33 // Forward public API methods from |proto| to their internal implementations. |
34 GuestViewContainer.forwardApiMethods = function(proto, apiMethods) { | 34 GuestViewContainer.forwardApiMethods = function(proto, apiMethods) { |
35 var createProtoHandler = function(m) { | 35 var createProtoHandler = function(m) { |
36 return function(var_args) { | 36 return function(var_args) { |
37 var internal = privates(this).internal; | 37 var internal = privates(this).internal; |
38 return $Function.apply(internal[m], internal, arguments); | 38 return $Function.apply(internal[m], internal, arguments); |
39 }; | 39 }; |
40 }; | 40 }; |
41 for (var i = 0; apiMethods[i]; ++i) { | 41 for (var i = 0; apiMethods[i]; ++i) { |
42 proto[apiMethods[i]] = createProtoHandler(apiMethods[i]); | 42 proto[apiMethods[i]] = createProtoHandler(apiMethods[i]); |
43 } | 43 } |
44 }; | 44 }; |
45 | 45 |
46 // Registers the browserplugin and guestview as custom elements once the | 46 // Registers the browserplugin and guestview as custom elements once the |
47 // document has loaded. | 47 // document has loaded. |
48 GuestViewContainer.registerElement = function(guestViewContainerType) { | 48 GuestViewContainer.registerElement = function(guestViewContainerType) { |
49 var useCapture = true; | 49 var useCapture = true; |
50 window.addEventListener('readystatechange', function listener(event) { | 50 window.addEventListener('readystatechange', function listener(event) { |
51 if (document.readyState == 'loading') | 51 if (document.readyState == 'loading') |
52 return; | 52 return; |
53 | 53 |
54 registerBrowserPluginElement( | 54 registerInternalElement(guestViewContainerType.VIEW_TYPE.toLowerCase()); |
55 guestViewContainerType.VIEW_TYPE.toLowerCase()); | |
56 registerGuestViewElement(guestViewContainerType); | 55 registerGuestViewElement(guestViewContainerType); |
57 window.removeEventListener(event.type, listener, useCapture); | 56 window.removeEventListener(event.type, listener, useCapture); |
58 }, useCapture); | 57 }, useCapture); |
59 }; | 58 }; |
60 | 59 |
61 // Create the 'guest' property to track new GuestViews and always listen for | 60 // Create the 'guest' property to track new GuestViews and always listen for |
62 // their resizes. | 61 // their resizes. |
63 GuestViewContainer.prototype.setupGuestProperty = function() { | 62 GuestViewContainer.prototype.setupGuestProperty = function() { |
64 $Object.defineProperty(this, 'guest', { | 63 $Object.defineProperty(this, 'guest', { |
65 get: function() { | 64 get: function() { |
(...skipping 11 matching lines...) Expand all Loading... |
77 contentResizeEvent.oldHeight = e.oldHeight; | 76 contentResizeEvent.oldHeight = e.oldHeight; |
78 contentResizeEvent.newWidth = e.newWidth; | 77 contentResizeEvent.newWidth = e.newWidth; |
79 contentResizeEvent.newHeight = e.newHeight; | 78 contentResizeEvent.newHeight = e.newHeight; |
80 this.dispatchEvent(contentResizeEvent); | 79 this.dispatchEvent(contentResizeEvent); |
81 }.bind(this); | 80 }.bind(this); |
82 }.bind(this), | 81 }.bind(this), |
83 enumerable: true | 82 enumerable: true |
84 }); | 83 }); |
85 }; | 84 }; |
86 | 85 |
87 GuestViewContainer.prototype.createBrowserPluginElement = function() { | 86 GuestViewContainer.prototype.createInternalElement$ = function() { |
88 // We create BrowserPlugin as a custom element in order to observe changes | 87 // We create BrowserPlugin as a custom element in order to observe changes |
89 // to attributes synchronously. | 88 // to attributes synchronously. |
90 var browserPluginElement = | 89 var browserPluginElement = |
91 new GuestViewContainer[this.viewType + 'BrowserPlugin'](); | 90 new GuestViewContainer[this.viewType + 'BrowserPlugin'](); |
92 privates(browserPluginElement).internal = this; | 91 privates(browserPluginElement).internal = this; |
93 return browserPluginElement; | 92 return browserPluginElement; |
94 }; | 93 }; |
95 | 94 |
96 GuestViewContainer.prototype.setupFocusPropagation = function() { | 95 GuestViewContainer.prototype.setupFocusPropagation = function() { |
97 if (!this.element.hasAttribute('tabIndex')) { | 96 if (!this.element.hasAttribute('tabIndex')) { |
98 // GuestViewContainer needs a tabIndex in order to be focusable. | 97 // GuestViewContainer needs a tabIndex in order to be focusable. |
99 // TODO(fsamuel): It would be nice to avoid exposing a tabIndex attribute | 98 // TODO(fsamuel): It would be nice to avoid exposing a tabIndex attribute |
100 // to allow GuestViewContainer to be focusable. | 99 // to allow GuestViewContainer to be focusable. |
101 // See http://crbug.com/231664. | 100 // See http://crbug.com/231664. |
102 this.element.setAttribute('tabIndex', -1); | 101 this.element.setAttribute('tabIndex', -1); |
103 } | 102 } |
104 this.element.addEventListener('focus', this.weakWrapper(function(e) { | 103 this.element.addEventListener('focus', this.weakWrapper(function(e) { |
105 // Focus the BrowserPlugin when the GuestViewContainer takes focus. | 104 // Focus the BrowserPlugin when the GuestViewContainer takes focus. |
106 privates(this).browserPluginElement.focus(); | 105 privates(this).internalElement.focus(); |
107 })); | 106 })); |
108 this.element.addEventListener('blur', this.weakWrapper(function(e) { | 107 this.element.addEventListener('blur', this.weakWrapper(function(e) { |
109 // Blur the BrowserPlugin when the GuestViewContainer loses focus. | 108 // Blur the BrowserPlugin when the GuestViewContainer loses focus. |
110 privates(this).browserPluginElement.blur(); | 109 privates(this).internalElement.blur(); |
111 })); | 110 })); |
112 }; | 111 }; |
113 | 112 |
114 GuestViewContainer.prototype.attachWindow = function() { | 113 GuestViewContainer.prototype.attachWindow$ = function() { |
115 if (!this.internalInstanceId) { | 114 if (!this.internalInstanceId) { |
116 return true; | 115 return true; |
117 } | 116 } |
118 | 117 |
119 this.guest.attach(this.internalInstanceId, | 118 this.guest.attach(this.internalInstanceId, |
120 this.viewInstanceId, | 119 this.viewInstanceId, |
121 this.buildParams()); | 120 this.buildParams()); |
122 return true; | 121 return true; |
123 }; | 122 }; |
124 | 123 |
125 GuestViewContainer.prototype.handleBrowserPluginAttributeMutation = | 124 GuestViewContainer.prototype.onInternalInstanceId = function( |
| 125 internalInstanceId) { |
| 126 this.internalInstanceId = internalInstanceId; |
| 127 |
| 128 // Track when the element resizes using the element resize callback. |
| 129 GuestViewInternalNatives.RegisterElementResizeCallback( |
| 130 this.internalInstanceId, this.weakWrapper(this.onElementResize)); |
| 131 |
| 132 if (!this.guest.getId()) { |
| 133 return; |
| 134 } |
| 135 this.guest.attach(this.internalInstanceId, |
| 136 this.viewInstanceId, |
| 137 this.buildParams()); |
| 138 }; |
| 139 |
| 140 GuestViewContainer.prototype.handleInternalElementAttributeMutation = |
126 function(name, oldValue, newValue) { | 141 function(name, oldValue, newValue) { |
127 if (name == 'internalinstanceid' && !oldValue && !!newValue) { | 142 if (name == 'internalinstanceid' && !oldValue && !!newValue) { |
128 privates(this).browserPluginElement.removeAttribute('internalinstanceid'); | 143 privates(this).internalElement.removeAttribute('internalinstanceid'); |
129 this.internalInstanceId = parseInt(newValue); | 144 this.onInternalInstanceId(parseInt(newValue)); |
130 | |
131 // Track when the element resizes using the element resize callback. | |
132 GuestViewInternalNatives.RegisterElementResizeCallback( | |
133 this.internalInstanceId, this.weakWrapper(this.onElementResize)); | |
134 | |
135 if (!this.guest.getId()) { | |
136 return; | |
137 } | |
138 this.guest.attach(this.internalInstanceId, | |
139 this.viewInstanceId, | |
140 this.buildParams()); | |
141 } | 145 } |
142 }; | 146 }; |
143 | 147 |
144 GuestViewContainer.prototype.onElementResize = function(newWidth, newHeight) { | 148 GuestViewContainer.prototype.onElementResize = function(newWidth, newHeight) { |
145 if (!this.guest.getId()) | 149 if (!this.guest.getId()) |
146 return; | 150 return; |
147 this.guest.setSize({normal: {width: newWidth, height: newHeight}}); | 151 this.guest.setSize({normal: {width: newWidth, height: newHeight}}); |
148 }; | 152 }; |
149 | 153 |
150 GuestViewContainer.prototype.buildParams = function() { | 154 GuestViewContainer.prototype.buildParams = function() { |
(...skipping 29 matching lines...) Expand all Loading... |
180 }; | 184 }; |
181 | 185 |
182 // Implemented by the specific view type, if needed. | 186 // Implemented by the specific view type, if needed. |
183 GuestViewContainer.prototype.buildContainerParams = function() { return {}; }; | 187 GuestViewContainer.prototype.buildContainerParams = function() { return {}; }; |
184 GuestViewContainer.prototype.onElementAttached = function() {}; | 188 GuestViewContainer.prototype.onElementAttached = function() {}; |
185 GuestViewContainer.prototype.onElementDetached = function() {}; | 189 GuestViewContainer.prototype.onElementDetached = function() {}; |
186 GuestViewContainer.prototype.setupAttributes = function() {}; | 190 GuestViewContainer.prototype.setupAttributes = function() {}; |
187 | 191 |
188 // Registers the browser plugin <object> custom element. |viewType| is the | 192 // Registers the browser plugin <object> custom element. |viewType| is the |
189 // name of the specific guestview container (e.g. 'webview'). | 193 // name of the specific guestview container (e.g. 'webview'). |
190 function registerBrowserPluginElement(viewType) { | 194 function registerInternalElement(viewType) { |
191 var proto = $Object.create(HTMLElement.prototype); | 195 var proto = $Object.create(HTMLElement.prototype); |
192 | 196 |
193 proto.createdCallback = function() { | 197 proto.createdCallback = function() { |
194 this.setAttribute('type', 'application/browser-plugin'); | 198 this.setAttribute('type', 'application/browser-plugin'); |
195 this.setAttribute('id', 'browser-plugin-' + IdGenerator.GetNextId()); | 199 this.setAttribute('id', 'browser-plugin-' + IdGenerator.GetNextId()); |
196 this.style.width = '100%'; | 200 this.style.width = '100%'; |
197 this.style.height = '100%'; | 201 this.style.height = '100%'; |
198 }; | 202 }; |
199 | 203 |
200 proto.attachedCallback = function() { | 204 proto.attachedCallback = function() { |
201 // Load the plugin immediately. | 205 // Load the plugin immediately. |
202 var unused = this.nonExistentAttribute; | 206 var unused = this.nonExistentAttribute; |
203 }; | 207 }; |
204 | 208 |
205 proto.attributeChangedCallback = function(name, oldValue, newValue) { | 209 proto.attributeChangedCallback = function(name, oldValue, newValue) { |
206 var internal = privates(this).internal; | 210 var internal = privates(this).internal; |
207 if (!internal) { | 211 if (!internal) { |
208 return; | 212 return; |
209 } | 213 } |
210 internal.handleBrowserPluginAttributeMutation(name, oldValue, newValue); | 214 internal.handleInternalElementAttributeMutation(name, oldValue, newValue); |
211 }; | 215 }; |
212 | 216 |
213 GuestViewContainer[viewType + 'BrowserPlugin'] = | 217 GuestViewContainer[viewType + 'BrowserPlugin'] = |
214 DocumentNatives.RegisterElement(viewType + 'browserplugin', | 218 DocumentNatives.RegisterElement(viewType + 'browserplugin', |
215 {extends: 'object', prototype: proto}); | 219 {extends: 'object', prototype: proto}); |
216 | 220 |
217 delete proto.createdCallback; | 221 delete proto.createdCallback; |
218 delete proto.attachedCallback; | 222 delete proto.attachedCallback; |
219 delete proto.detachedCallback; | 223 delete proto.detachedCallback; |
220 delete proto.attributeChangedCallback; | 224 delete proto.attributeChangedCallback; |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 // Delete the callbacks so developers cannot call them and produce unexpected | 278 // Delete the callbacks so developers cannot call them and produce unexpected |
275 // behavior. | 279 // behavior. |
276 delete proto.createdCallback; | 280 delete proto.createdCallback; |
277 delete proto.attachedCallback; | 281 delete proto.attachedCallback; |
278 delete proto.detachedCallback; | 282 delete proto.detachedCallback; |
279 delete proto.attributeChangedCallback; | 283 delete proto.attributeChangedCallback; |
280 } | 284 } |
281 | 285 |
282 // Exports. | 286 // Exports. |
283 exports.GuestViewContainer = GuestViewContainer; | 287 exports.GuestViewContainer = GuestViewContainer; |
OLD | NEW |