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

Side by Side Diff: chrome/renderer/resources/extensions/ad_view.js

Issue 327363002: Remove adview (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: More files deleted! Created 6 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
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Shim that simulates a <adview> tag via Mutation Observers.
6 //
7 // The actual tag is implemented via the browser plugin. The internals of this
8 // are hidden via Shadow DOM.
9
10 // TODO(rpaquay): This file is currently very similar to "web_view.js". Do we
11 // want to refactor to extract common pieces?
12
13 var eventBindings = require('event_bindings');
14 var process = requireNative('process');
15 var addTagWatcher = require('tagWatcher').addTagWatcher;
16
17 /**
18 * List of attribute names to "blindly" sync between <adview> tag and internal
19 * browser plugin.
20 */
21 var AD_VIEW_ATTRIBUTES = [
22 'name',
23 ];
24
25 /**
26 * List of custom attributes (and their behavior).
27 *
28 * name: attribute name.
29 * onMutation(adview, mutation): callback invoked when attribute is mutated.
30 * isProperty: True if the attribute should be exposed as a property.
31 */
32 var AD_VIEW_CUSTOM_ATTRIBUTES = [
33 {
34 name: 'ad-network',
35 onMutation: function(adview, mutation) {
36 adview.handleAdNetworkMutation(mutation);
37 },
38 isProperty: function() {
39 return true;
40 }
41 }
42 ];
43
44 /**
45 * List of api methods. These are forwarded to the browser plugin.
46 */
47 var AD_VIEW_API_METHODS = [
48 // Empty for now.
49 ];
50
51 var createEvent = function(name) {
52 var eventOpts = {supportsListeners: true, supportsFilters: true};
53 return new eventBindings.Event(name, undefined, eventOpts);
54 };
55
56 var AdviewLoadAbortEvent = createEvent('adview.onLoadAbort');
57 var AdviewLoadCommitEvent = createEvent('adview.onLoadCommit');
58
59 var AD_VIEW_EXT_EVENTS = {
60 'loadabort': {
61 evt: AdviewLoadAbortEvent,
62 fields: ['url', 'isTopLevel', 'reason']
63 },
64 'loadcommit': {
65 evt: AdviewLoadCommitEvent,
66 fields: ['url', 'isTopLevel']
67 }
68 };
69
70 /**
71 * List of supported ad-networks.
72 *
73 * name: identifier of the ad-network, corresponding to a valid value
74 * of the "ad-network" attribute of an <adview> element.
75 * url: url to navigate to when initially displaying the <adview>.
76 * origin: origin of urls the <adview> is allowed navigate to.
77 */
78 var AD_VIEW_AD_NETWORKS_WHITELIST = [
79 {
80 name: 'admob',
81 url: 'https://admob-sdk.doubleclick.net/chromeapps',
82 origin: 'https://double.net'
83 },
84 ];
85
86 /**
87 * Return the whitelisted ad-network entry named |name|.
88 */
89 function getAdNetworkInfo(name) {
90 var result = null;
91 $Array.forEach(AD_VIEW_AD_NETWORKS_WHITELIST, function(item) {
92 if (item.name === name)
93 result = item;
94 });
95 return result;
96 }
97
98 /**
99 * @constructor
100 */
101 function AdView(adviewNode) {
102 this.adviewNode_ = adviewNode;
103 this.browserPluginNode_ = this.createBrowserPluginNode_();
104 var shadowRoot = this.adviewNode_.createShadowRoot();
105 shadowRoot.appendChild(this.browserPluginNode_);
106
107 this.setupCustomAttributes_();
108 this.setupAdviewNodeObservers_();
109 this.setupAdviewNodeMethods_();
110 this.setupAdviewNodeProperties_();
111 this.setupAdviewNodeEvents_();
112 this.setupBrowserPluginNodeObservers_();
113 }
114
115 /**
116 * @private
117 */
118 AdView.prototype.createBrowserPluginNode_ = function() {
119 var browserPluginNode = document.createElement('object');
120 browserPluginNode.type = 'application/browser-plugin';
121 // The <object> node fills in the <adview> container.
122 browserPluginNode.style.width = '100%';
123 browserPluginNode.style.height = '100%';
124 $Array.forEach(AD_VIEW_ATTRIBUTES, function(attributeName) {
125 // Only copy attributes that have been assigned values, rather than copying
126 // a series of undefined attributes to BrowserPlugin.
127 if (this.adviewNode_.hasAttribute(attributeName)) {
128 browserPluginNode.setAttribute(
129 attributeName, this.adviewNode_.getAttribute(attributeName));
130 }
131 }, this);
132
133 return browserPluginNode;
134 }
135
136 /**
137 * @private
138 */
139 AdView.prototype.setupCustomAttributes_ = function() {
140 $Array.forEach(AD_VIEW_CUSTOM_ATTRIBUTES, function(attributeInfo) {
141 if (attributeInfo.onMutation) {
142 attributeInfo.onMutation(this);
143 }
144 }, this);
145 }
146
147 /**
148 * @private
149 */
150 AdView.prototype.setupAdviewNodeMethods_ = function() {
151 // this.browserPluginNode_[apiMethod] are not necessarily defined immediately
152 // after the shadow object is appended to the shadow root.
153 var self = this;
154 $Array.forEach(AD_VIEW_API_METHODS, function(apiMethod) {
155 self.adviewNode_[apiMethod] = function(var_args) {
156 return $Function.apply(self.browserPluginNode_[apiMethod],
157 self.browserPluginNode_, arguments);
158 };
159 }, this);
160 }
161
162 /**
163 * @private
164 */
165 AdView.prototype.setupAdviewNodeObservers_ = function() {
166 // Map attribute modifications on the <adview> tag to property changes in
167 // the underlying <object> node.
168 var handleMutation = $Function.bind(function(mutation) {
169 this.handleAdviewAttributeMutation_(mutation);
170 }, this);
171 var observer = new MutationObserver(function(mutations) {
172 $Array.forEach(mutations, handleMutation);
173 });
174 observer.observe(
175 this.adviewNode_,
176 {attributes: true, attributeFilter: AD_VIEW_ATTRIBUTES});
177
178 this.setupAdviewNodeCustomObservers_();
179 }
180
181 /**
182 * @private
183 */
184 AdView.prototype.setupAdviewNodeCustomObservers_ = function() {
185 var handleMutation = $Function.bind(function(mutation) {
186 this.handleAdviewCustomAttributeMutation_(mutation);
187 }, this);
188 var observer = new MutationObserver(function(mutations) {
189 $Array.forEach(mutations, handleMutation);
190 });
191 var customAttributeNames =
192 AD_VIEW_CUSTOM_ATTRIBUTES.map(function(item) { return item.name; });
193 observer.observe(
194 this.adviewNode_,
195 {attributes: true, attributeFilter: customAttributeNames});
196 }
197
198 /**
199 * @private
200 */
201 AdView.prototype.setupBrowserPluginNodeObservers_ = function() {
202 var handleMutation = $Function.bind(function(mutation) {
203 this.handleBrowserPluginAttributeMutation_(mutation);
204 }, this);
205 var objectObserver = new MutationObserver(function(mutations) {
206 $Array.forEach(mutations, handleMutation);
207 });
208 objectObserver.observe(
209 this.browserPluginNode_,
210 {attributes: true, attributeFilter: AD_VIEW_ATTRIBUTES});
211 }
212
213 /**
214 * @private
215 */
216 AdView.prototype.setupAdviewNodeProperties_ = function() {
217 var browserPluginNode = this.browserPluginNode_;
218 // Expose getters and setters for the attributes.
219 $Array.forEach(AD_VIEW_ATTRIBUTES, function(attributeName) {
220 Object.defineProperty(this.adviewNode_, attributeName, {
221 get: function() {
222 return browserPluginNode[attributeName];
223 },
224 set: function(value) {
225 browserPluginNode[attributeName] = value;
226 },
227 enumerable: true
228 });
229 }, this);
230
231 // Expose getters and setters for the custom attributes.
232 var adviewNode = this.adviewNode_;
233 $Array.forEach(AD_VIEW_CUSTOM_ATTRIBUTES, function(attributeInfo) {
234 if (attributeInfo.isProperty()) {
235 var attributeName = attributeInfo.name;
236 Object.defineProperty(this.adviewNode_, attributeName, {
237 get: function() {
238 return adviewNode.getAttribute(attributeName);
239 },
240 set: function(value) {
241 adviewNode.setAttribute(attributeName, value);
242 },
243 enumerable: true
244 });
245 }
246 }, this);
247
248 this.setupAdviewContentWindowProperty_();
249 }
250
251 /**
252 * @private
253 */
254 AdView.prototype.setupAdviewContentWindowProperty_ = function() {
255 var browserPluginNode = this.browserPluginNode_;
256 // We cannot use {writable: true} property descriptor because we want dynamic
257 // getter value.
258 Object.defineProperty(this.adviewNode_, 'contentWindow', {
259 get: function() {
260 // TODO(fsamuel): This is a workaround to enable
261 // contentWindow.postMessage until http://crbug.com/152006 is fixed.
262 if (browserPluginNode.contentWindow)
263 return browserPluginNode.contentWindow.self;
264 console.error('contentWindow is not available at this time. ' +
265 'It will become available when the page has finished loading.');
266 },
267 // No setter.
268 enumerable: true
269 });
270 }
271
272 /**
273 * @private
274 */
275 AdView.prototype.handleAdviewAttributeMutation_ = function(mutation) {
276 // This observer monitors mutations to attributes of the <adview> and
277 // updates the BrowserPlugin properties accordingly. In turn, updating
278 // a BrowserPlugin property will update the corresponding BrowserPlugin
279 // attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more
280 // details.
281 this.browserPluginNode_[mutation.attributeName] =
282 this.adviewNode_.getAttribute(mutation.attributeName);
283 };
284
285 /**
286 * @private
287 */
288 AdView.prototype.handleAdviewCustomAttributeMutation_ = function(mutation) {
289 $Array.forEach(AD_VIEW_CUSTOM_ATTRIBUTES, function(item) {
290 if (mutation.attributeName.toUpperCase() == item.name.toUpperCase()) {
291 if (item.onMutation) {
292 $Function.bind(item.onMutation, item)(this, mutation);
293 }
294 }
295 }, this);
296 };
297
298 /**
299 * @private
300 */
301 AdView.prototype.handleBrowserPluginAttributeMutation_ = function(mutation) {
302 // This observer monitors mutations to attributes of the BrowserPlugin and
303 // updates the <adview> attributes accordingly.
304 if (!this.browserPluginNode_.hasAttribute(mutation.attributeName)) {
305 // If an attribute is removed from the BrowserPlugin, then remove it
306 // from the <adview> as well.
307 this.adviewNode_.removeAttribute(mutation.attributeName);
308 } else {
309 // Update the <adview> attribute to match the BrowserPlugin attribute.
310 // Note: Calling setAttribute on <adview> will trigger its mutation
311 // observer which will then propagate that attribute to BrowserPlugin. In
312 // cases where we permit assigning a BrowserPlugin attribute the same value
313 // again (such as navigation when crashed), this could end up in an infinite
314 // loop. Thus, we avoid this loop by only updating the <adview> attribute
315 // if the BrowserPlugin attributes differs from it.
316 var oldValue = this.adviewNode_.getAttribute(mutation.attributeName);
317 var newValue = this.browserPluginNode_.getAttribute(mutation.attributeName);
318 if (newValue != oldValue) {
319 this.adviewNode_.setAttribute(mutation.attributeName, newValue);
320 }
321 }
322 };
323
324 /**
325 * @public
326 */
327 AdView.prototype.handleAdNetworkMutation = function(mutation) {
328 if (this.adviewNode_.hasAttribute('ad-network')) {
329 var value = this.adviewNode_.getAttribute('ad-network');
330 var item = getAdNetworkInfo(value);
331 if (!item) {
332 // Ignore the new attribute value and set it to empty string.
333 // Avoid infinite loop by checking for empty string as new value.
334 if (value != '') {
335 console.error('The ad-network "' + value + '" is not recognized.');
336 this.adviewNode_.setAttribute('ad-network', '');
337 }
338 }
339 }
340 }
341
342 /**
343 * @private
344 */
345 AdView.prototype.setupAdviewNodeEvents_ = function() {
346 var self = this;
347 var onInstanceIdAllocated = function(e) {
348 var detail = e.detail ? JSON.parse(e.detail) : {};
349 self.instanceId_ = detail.windowId;
350 var params = {
351 'api': 'adview'
352 };
353 self.browserPluginNode_['-internal-attach'](params);
354
355 for (var eventName in AD_VIEW_EXT_EVENTS) {
356 self.setupExtEvent_(eventName, AD_VIEW_EXT_EVENTS[eventName]);
357 }
358 };
359 this.browserPluginNode_.addEventListener('-internal-instanceid-allocated',
360 onInstanceIdAllocated);
361 }
362
363 /**
364 * @private
365 */
366 AdView.prototype.setupExtEvent_ = function(eventName, eventInfo) {
367 var self = this;
368 var adviewNode = this.adviewNode_;
369 eventInfo.evt.addListener(function(event) {
370 var adviewEvent = new Event(eventName, {bubbles: true});
371 $Array.forEach(eventInfo.fields, function(field) {
372 adviewEvent[field] = event[field];
373 });
374 if (eventInfo.customHandler) {
375 eventInfo.customHandler(self, event);
376 }
377 adviewNode.dispatchEvent(adviewEvent);
378 }, {instanceId: self.instanceId_});
379 };
380
381 /**
382 * @public
383 */
384 AdView.prototype.dispatchEvent = function(eventname, detail) {
385 // Create event object.
386 var evt = new Event(eventname, { bubbles: true });
387 for(var item in detail) {
388 evt[item] = detail[item];
389 }
390
391 // Dispatch event.
392 this.adviewNode_.dispatchEvent(evt);
393 }
394
395 addTagWatcher('ADVIEW', function(addedNode) { new AdView(addedNode); });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698