Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10)

Side by Side Diff: extensions/renderer/resources/guest_view/guest_view_container.js

Issue 1165773004: Extract the element implementation logic to function mods in <webview>. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@qui
Patch Set: sync @tott Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 var MessagingNatives = requireNative('messaging_natives'); 12 var MessagingNatives = requireNative('messaging_natives');
13 13
14 function GuestViewContainer(element, viewType) { 14 function GuestViewContainer(element, viewType) {
15 privates(element).internal = this; 15 privates(element).internal = this;
16 this.attributes = {}; 16 this.attributes = {};
17 this.element = element; 17 this.element = element;
18 this.elementAttached = false; 18 this.elementAttached = false;
19 this.viewInstanceId = IdGenerator.GetNextId(); 19 this.viewInstanceId = IdGenerator.GetNextId();
20 this.viewType = viewType; 20 this.viewType = viewType;
21 21
22 this.setupGuestProperty(); 22 this.setupGuestProperty();
23 this.guest = new GuestView(viewType); 23 this.guest = new GuestView(viewType);
24 this.setupAttributes(); 24 this.setupAttributes();
25 25
26 privates(this).browserPluginElement = this.createBrowserPluginElement(); 26 privates(this).internalElement = this.createInternalElement$();
27 this.setupFocusPropagation(); 27 this.setupFocusPropagation();
28 var shadowRoot = this.element.createShadowRoot(); 28 var shadowRoot = this.element.createShadowRoot();
29 shadowRoot.appendChild(privates(this).browserPluginElement); 29 shadowRoot.appendChild(privates(this).internalElement);
30 30
31 GuestViewInternalNatives.RegisterView(this.viewInstanceId, this); 31 GuestViewInternalNatives.RegisterView(this.viewInstanceId, this);
32 } 32 }
33 33
34 // Forward public API methods from |proto| to their internal implementations. 34 // Forward public API methods from |proto| to their internal implementations.
35 GuestViewContainer.forwardApiMethods = function(proto, apiMethods) { 35 GuestViewContainer.forwardApiMethods = function(proto, apiMethods) {
36 var createProtoHandler = function(m) { 36 var createProtoHandler = function(m) {
37 return function(var_args) { 37 return function(var_args) {
38 var internal = privates(this).internal; 38 var internal = privates(this).internal;
39 return $Function.apply(internal[m], internal, arguments); 39 return $Function.apply(internal[m], internal, arguments);
40 }; 40 };
41 }; 41 };
42 for (var i = 0; apiMethods[i]; ++i) { 42 for (var i = 0; apiMethods[i]; ++i) {
43 proto[apiMethods[i]] = createProtoHandler(apiMethods[i]); 43 proto[apiMethods[i]] = createProtoHandler(apiMethods[i]);
44 } 44 }
45 }; 45 };
46 46
47 // Registers the browserplugin and guestview as custom elements once the 47 // Registers the browserplugin and guestview as custom elements once the
48 // document has loaded. 48 // document has loaded.
49 GuestViewContainer.registerElement = function(guestViewContainerType) { 49 GuestViewContainer.registerElement = function(guestViewContainerType) {
50 var useCapture = true; 50 var useCapture = true;
51 window.addEventListener('readystatechange', function listener(event) { 51 window.addEventListener('readystatechange', function listener(event) {
52 if (document.readyState == 'loading') 52 if (document.readyState == 'loading')
53 return; 53 return;
54 54
55 registerBrowserPluginElement( 55 registerInternalElement(guestViewContainerType.VIEW_TYPE.toLowerCase());
56 guestViewContainerType.VIEW_TYPE.toLowerCase());
57 registerGuestViewElement(guestViewContainerType); 56 registerGuestViewElement(guestViewContainerType);
58 window.removeEventListener(event.type, listener, useCapture); 57 window.removeEventListener(event.type, listener, useCapture);
59 }, useCapture); 58 }, useCapture);
60 }; 59 };
61 60
62 // Create the 'guest' property to track new GuestViews and always listen for 61 // Create the 'guest' property to track new GuestViews and always listen for
63 // their resizes. 62 // their resizes.
64 GuestViewContainer.prototype.setupGuestProperty = function() { 63 GuestViewContainer.prototype.setupGuestProperty = function() {
65 $Object.defineProperty(this, 'guest', { 64 $Object.defineProperty(this, 'guest', {
66 get: function() { 65 get: function() {
(...skipping 11 matching lines...) Expand all
78 contentResizeEvent.oldHeight = e.oldHeight; 77 contentResizeEvent.oldHeight = e.oldHeight;
79 contentResizeEvent.newWidth = e.newWidth; 78 contentResizeEvent.newWidth = e.newWidth;
80 contentResizeEvent.newHeight = e.newHeight; 79 contentResizeEvent.newHeight = e.newHeight;
81 this.dispatchEvent(contentResizeEvent); 80 this.dispatchEvent(contentResizeEvent);
82 }.bind(this); 81 }.bind(this);
83 }.bind(this), 82 }.bind(this),
84 enumerable: true 83 enumerable: true
85 }); 84 });
86 }; 85 };
87 86
88 GuestViewContainer.prototype.createBrowserPluginElement = function() { 87 GuestViewContainer.prototype.createInternalElement$ = function() {
89 // We create BrowserPlugin as a custom element in order to observe changes 88 // We create BrowserPlugin as a custom element in order to observe changes
90 // to attributes synchronously. 89 // to attributes synchronously.
91 var browserPluginElement = 90 var browserPluginElement =
92 new GuestViewContainer[this.viewType + 'BrowserPlugin'](); 91 new GuestViewContainer[this.viewType + 'BrowserPlugin']();
93 privates(browserPluginElement).internal = this; 92 privates(browserPluginElement).internal = this;
94 return browserPluginElement; 93 return browserPluginElement;
95 }; 94 };
96 95
97 GuestViewContainer.prototype.setupFocusPropagation = function() { 96 GuestViewContainer.prototype.setupFocusPropagation = function() {
98 if (!this.element.hasAttribute('tabIndex')) { 97 if (!this.element.hasAttribute('tabIndex')) {
99 // GuestViewContainer needs a tabIndex in order to be focusable. 98 // GuestViewContainer needs a tabIndex in order to be focusable.
100 // TODO(fsamuel): It would be nice to avoid exposing a tabIndex attribute 99 // TODO(fsamuel): It would be nice to avoid exposing a tabIndex attribute
101 // to allow GuestViewContainer to be focusable. 100 // to allow GuestViewContainer to be focusable.
102 // See http://crbug.com/231664. 101 // See http://crbug.com/231664.
103 this.element.setAttribute('tabIndex', -1); 102 this.element.setAttribute('tabIndex', -1);
104 } 103 }
105 this.element.addEventListener('focus', this.weakWrapper(function(e) { 104 this.element.addEventListener('focus', this.weakWrapper(function(e) {
106 // Focus the BrowserPlugin when the GuestViewContainer takes focus. 105 // Focus the BrowserPlugin when the GuestViewContainer takes focus.
107 privates(this).browserPluginElement.focus(); 106 privates(this).internalElement.focus();
108 })); 107 }));
109 this.element.addEventListener('blur', this.weakWrapper(function(e) { 108 this.element.addEventListener('blur', this.weakWrapper(function(e) {
110 // Blur the BrowserPlugin when the GuestViewContainer loses focus. 109 // Blur the BrowserPlugin when the GuestViewContainer loses focus.
111 privates(this).browserPluginElement.blur(); 110 privates(this).internalElement.blur();
112 })); 111 }));
113 }; 112 };
114 113
115 GuestViewContainer.prototype.attachWindow = function() { 114 GuestViewContainer.prototype.attachWindow$ = function() {
116 if (!this.internalInstanceId) { 115 if (!this.internalInstanceId) {
117 return true; 116 return true;
118 } 117 }
119 118
120 this.guest.attach(this.internalInstanceId, 119 this.guest.attach(this.internalInstanceId,
121 this.viewInstanceId, 120 this.viewInstanceId,
122 this.buildParams()); 121 this.buildParams());
123 return true; 122 return true;
124 }; 123 };
125 124
126 GuestViewContainer.prototype.makeGCOwnContainer = function(internalInstanceId) { 125 GuestViewContainer.prototype.makeGCOwnContainer = function(internalInstanceId) {
127 MessagingNatives.BindToGC(this, function() { 126 MessagingNatives.BindToGC(this, function() {
128 GuestViewInternalNatives.DestroyContainer(internalInstanceId); 127 GuestViewInternalNatives.DestroyContainer(internalInstanceId);
129 }, -1); 128 }, -1);
130 }; 129 };
131 130
132 GuestViewContainer.prototype.handleBrowserPluginAttributeMutation = 131 GuestViewContainer.prototype.onInternalInstanceId = function(
132 internalInstanceId) {
133 this.internalInstanceId = internalInstanceId;
134 this.makeGCOwnContainer(this.internalInstanceId);
135
136 // Track when the element resizes using the element resize callback.
137 GuestViewInternalNatives.RegisterElementResizeCallback(
138 this.internalInstanceId, this.weakWrapper(this.onElementResize));
139
140 if (!this.guest.getId()) {
141 return;
142 }
143 this.guest.attach(this.internalInstanceId,
144 this.viewInstanceId,
145 this.buildParams());
146 };
147
148 GuestViewContainer.prototype.handleInternalElementAttributeMutation =
133 function(name, oldValue, newValue) { 149 function(name, oldValue, newValue) {
134 if (name == 'internalinstanceid' && !oldValue && !!newValue) { 150 if (name == 'internalinstanceid' && !oldValue && !!newValue) {
135 privates(this).browserPluginElement.removeAttribute('internalinstanceid'); 151 privates(this).internalElement.removeAttribute('internalinstanceid');
136 this.internalInstanceId = parseInt(newValue); 152 this.onInternalInstanceId(parseInt(newValue));
137
138 this.makeGCOwnContainer(this.internalInstanceId);
139
140 // Track when the element resizes using the element resize callback.
141 GuestViewInternalNatives.RegisterElementResizeCallback(
142 this.internalInstanceId, this.weakWrapper(this.onElementResize));
143
144 if (!this.guest.getId()) {
145 return;
146 }
147 this.guest.attach(this.internalInstanceId,
148 this.viewInstanceId,
149 this.buildParams());
150 } 153 }
151 }; 154 };
152 155
153 GuestViewContainer.prototype.onElementResize = function(newWidth, newHeight) { 156 GuestViewContainer.prototype.onElementResize = function(newWidth, newHeight) {
154 if (!this.guest.getId()) 157 if (!this.guest.getId())
155 return; 158 return;
156 this.guest.setSize({normal: {width: newWidth, height: newHeight}}); 159 this.guest.setSize({normal: {width: newWidth, height: newHeight}});
157 }; 160 };
158 161
159 GuestViewContainer.prototype.buildParams = function() { 162 GuestViewContainer.prototype.buildParams = function() {
(...skipping 29 matching lines...) Expand all
189 }; 192 };
190 193
191 // Implemented by the specific view type, if needed. 194 // Implemented by the specific view type, if needed.
192 GuestViewContainer.prototype.buildContainerParams = function() { return {}; }; 195 GuestViewContainer.prototype.buildContainerParams = function() { return {}; };
193 GuestViewContainer.prototype.onElementAttached = function() {}; 196 GuestViewContainer.prototype.onElementAttached = function() {};
194 GuestViewContainer.prototype.onElementDetached = function() {}; 197 GuestViewContainer.prototype.onElementDetached = function() {};
195 GuestViewContainer.prototype.setupAttributes = function() {}; 198 GuestViewContainer.prototype.setupAttributes = function() {};
196 199
197 // Registers the browser plugin <object> custom element. |viewType| is the 200 // Registers the browser plugin <object> custom element. |viewType| is the
198 // name of the specific guestview container (e.g. 'webview'). 201 // name of the specific guestview container (e.g. 'webview').
199 function registerBrowserPluginElement(viewType) { 202 function registerInternalElement(viewType) {
200 var proto = $Object.create(HTMLElement.prototype); 203 var proto = $Object.create(HTMLElement.prototype);
201 204
202 proto.createdCallback = function() { 205 proto.createdCallback = function() {
203 this.setAttribute('type', 'application/browser-plugin'); 206 this.setAttribute('type', 'application/browser-plugin');
204 this.setAttribute('id', 'browser-plugin-' + IdGenerator.GetNextId()); 207 this.setAttribute('id', 'browser-plugin-' + IdGenerator.GetNextId());
205 this.style.width = '100%'; 208 this.style.width = '100%';
206 this.style.height = '100%'; 209 this.style.height = '100%';
207 }; 210 };
208 211
209 proto.attachedCallback = function() { 212 proto.attachedCallback = function() {
210 // Load the plugin immediately. 213 // Load the plugin immediately.
211 var unused = this.nonExistentAttribute; 214 var unused = this.nonExistentAttribute;
212 }; 215 };
213 216
214 proto.attributeChangedCallback = function(name, oldValue, newValue) { 217 proto.attributeChangedCallback = function(name, oldValue, newValue) {
215 var internal = privates(this).internal; 218 var internal = privates(this).internal;
216 if (!internal) { 219 if (!internal) {
217 return; 220 return;
218 } 221 }
219 internal.handleBrowserPluginAttributeMutation(name, oldValue, newValue); 222 internal.handleInternalElementAttributeMutation(name, oldValue, newValue);
220 }; 223 };
221 224
222 GuestViewContainer[viewType + 'BrowserPlugin'] = 225 GuestViewContainer[viewType + 'BrowserPlugin'] =
223 DocumentNatives.RegisterElement(viewType + 'browserplugin', 226 DocumentNatives.RegisterElement(viewType + 'browserplugin',
224 {extends: 'object', prototype: proto}); 227 {extends: 'object', prototype: proto});
225 228
226 delete proto.createdCallback; 229 delete proto.createdCallback;
227 delete proto.attachedCallback; 230 delete proto.attachedCallback;
228 delete proto.detachedCallback; 231 delete proto.detachedCallback;
229 delete proto.attributeChangedCallback; 232 delete proto.attributeChangedCallback;
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 // Delete the callbacks so developers cannot call them and produce unexpected 286 // Delete the callbacks so developers cannot call them and produce unexpected
284 // behavior. 287 // behavior.
285 delete proto.createdCallback; 288 delete proto.createdCallback;
286 delete proto.attachedCallback; 289 delete proto.attachedCallback;
287 delete proto.detachedCallback; 290 delete proto.detachedCallback;
288 delete proto.attributeChangedCallback; 291 delete proto.attributeChangedCallback;
289 } 292 }
290 293
291 // Exports. 294 // Exports.
292 exports.GuestViewContainer = GuestViewContainer; 295 exports.GuestViewContainer = GuestViewContainer;
OLDNEW
« no previous file with comments | « extensions/renderer/resources/guest_view/guest_view.js ('k') | extensions/renderer/resources/guest_view/guest_view_iframe.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698