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

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

Issue 12967016: Improve <adview> implementation and add tests. (Closed) Base URL: https://git.chromium.org/chromium/src.git@master
Patch Set: Fix comment. Created 7 years, 9 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 (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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 // Shim that simulates a <adview> tag via Mutation Observers. 5 // Shim that simulates a <adview> tag via Mutation Observers.
6 // 6 //
7 // The actual tag is implemented via the browser plugin. The internals of this 7 // The actual tag is implemented via the browser plugin. The internals of this
8 // are hidden via Shadow DOM. 8 // are hidden via Shadow DOM.
9 9
10 // TODO(rpaquay): This file is currently very similar to "web_view.js". Do we 10 // TODO(rpaquay): This file is currently very similar to "web_view.js". Do we
11 // want to refactor to extract common pieces? 11 // want to refactor to extract common pieces?
12 12
13
13 var adViewCustom = require('adViewCustom'); 14 var adViewCustom = require('adViewCustom');
14 var chrome = requireNative('chrome').GetChrome(); 15 var chrome = requireNative('chrome').GetChrome();
15 var forEach = require('utils').forEach; 16 var forEach = require('utils').forEach;
16 var watchForTag = require('tagWatcher').watchForTag; 17 var watchForTag = require('tagWatcher').watchForTag;
17 18
18 19
20 /**
21 * Define "allowCustomAdNetworks" function such that it returns "true" if the
22 * "adViewCustom" module was injected. This is so that the
23 * "kEnableAdviewSrcAttribute" flag is respected.
24 */
19 var allowCustomAdNetworks = (function(allow){ 25 var allowCustomAdNetworks = (function(allow){
20 return function() { return Boolean(allow); } 26 return function() { return Boolean(allow); }
21 })(adViewCustom ? adViewCustom.enabled : false); 27 })(adViewCustom ? adViewCustom.enabled : false);
22 28
23 29
24 // List of attribute names to "blindly" sync between <adview> tag and internal 30 /**
25 // browser plugin. 31 * List of attribute names to "blindly" sync between <adview> tag and internal
32 * browser plugin.
33 */
26 var AD_VIEW_ATTRIBUTES = [ 34 var AD_VIEW_ATTRIBUTES = [
27 'name', 35 'name',
28 ]; 36 ];
29 37
30 // List of custom attributes (and their behavior) 38 /**
31 // 39 * List of custom attributes (and their behavior).
32 // name: attribute name. 40 *
33 // onInit(adview): callback invoked when the <adview> element is created. 41 * name: attribute name.
34 // onMutate(adview, mutation): callback invoked when attribute is mutated. 42 * onMutation(adview, mutation): callback invoked when attribute is mutated.
43 * isProperty: True if the attribute should be exposed as a property.
44 */
35 var AD_VIEW_CUSTOM_ATTRIBUTES = [ 45 var AD_VIEW_CUSTOM_ATTRIBUTES = [
36 { 46 {
37 'name': "ad-network", 47 name: 'ad-network',
38 'onInit': function(adview) { 48 onMutation: function(adview, mutation) {
39 if (adview.node_.hasAttribute(this.name)) { 49 adview.handleAdNetworkMutation(mutation);
40 var value = adview.node_.getAttribute(this.name); 50 },
41 var item = getAdNetworkInfo(value); 51 isProperty: function() {
42 if (item) { 52 return true;
43 adview.objectNode_.setAttribute("src", item.url);
44 }
45 else if (allowCustomAdNetworks()) {
46 console.log('The ad-network \"' + value + '\" is not recognized, ' +
47 'but custom ad-networks are enabled.');
48 }
49 else {
50 console.error('The ad-network \"' + value + '\" is not recognized.');
51 }
52 }
53 } 53 }
54 }, 54 },
55 { 55 {
56 'name': "src", 56 name: 'src',
57 'onInit': function(adview) { 57 onMutation: function(adview, mutation) {
58 if (allowCustomAdNetworks()) { 58 adview.handleSrcMutation(mutation);
59 if (adview.node_.hasAttribute(this.name)) {
60 var newValue = adview.node_.getAttribute(this.name);
61 adview.objectNode_.setAttribute("src", newValue);
62 }
63 }
64 }, 59 },
65 'onMutation': function(adview, mutation) { 60 isProperty: function() {
66 if (allowCustomAdNetworks()) { 61 return allowCustomAdNetworks();
67 if (adview.node_.hasAttribute(this.name)) {
68 var newValue = adview.node_.getAttribute(this.name);
69 // Note: setAttribute does not work as intended here.
70 //adview.objectNode_.setAttribute(this.name, newValue);
71 adview.objectNode_[this.name] = newValue;
72 }
73 else {
74 // If an attribute is removed from the BrowserPlugin, then remove it
75 // from the <adview> as well.
76 this.objectNode_.removeAttribute(this.name);
77 }
78 }
79 } 62 }
80 } 63 }
81 ]; 64 ];
82 65
83 // List of api methods. These are forwarded to the browser plugin. 66 /**
67 * List of api methods. These are forwarded to the browser plugin.
68 */
84 var AD_VIEW_API_METHODS = [ 69 var AD_VIEW_API_METHODS = [
85 // Empty for now. 70 // Empty for now.
86 ]; 71 ];
87 72
88 // List of events to blindly forward from the browser plugin to the <adview>. 73 /**
74 * List of events to blindly forward from the browser plugin to the <adview>.
75 */
89 var AD_VIEW_EVENTS = { 76 var AD_VIEW_EVENTS = {
90 'loadcommit' : [], 77 'loadabort' : ['url', 'isTopLevel', 'reason'],
78 'loadcommit' : ['url', 'isTopLevel'],
91 'sizechanged': ['oldHeight', 'oldWidth', 'newHeight', 'newWidth'], 79 'sizechanged': ['oldHeight', 'oldWidth', 'newHeight', 'newWidth'],
92 }; 80 };
93 81
94 // List of supported ad-networks. 82 /**
95 // 83 * List of supported ad-networks.
96 // name: identifier of the ad-network, corresponding to a valid value 84 *
97 // of the "ad-network" attribute of an <adview> element. 85 * name: identifier of the ad-network, corresponding to a valid value
98 // url: url to navigate to when initially displaying the <adview>. 86 * of the "ad-network" attribute of an <adview> element.
99 // origin: origin of urls the <adview> is allowed navigate to. 87 * url: url to navigate to when initially displaying the <adview>.
88 * origin: origin of urls the <adview> is allowed navigate to.
89 */
100 var AD_VIEW_AD_NETWORKS_WHITELIST = [ 90 var AD_VIEW_AD_NETWORKS_WHITELIST = [
101 { 91 {
102 'name': 'admob', 92 name: 'admob',
103 'url': 'https://admob-sdk.doubleclick.net/chromeapps', 93 url: 'https://admob-sdk.doubleclick.net/chromeapps',
104 'origin': 'https://double.net' 94 origin: 'https://double.net'
105 }, 95 },
106 ]; 96 ];
107 97
108 // 98 /**
109 // Return the whitelisted ad-network entry named |name|. 99 * Return the whitelisted ad-network entry named |name|.
110 // 100 */
111 function getAdNetworkInfo(name) { 101 function getAdNetworkInfo(name) {
112 var result = null; 102 var result = null;
113 forEach(AD_VIEW_AD_NETWORKS_WHITELIST, function(i, item) { 103 forEach(AD_VIEW_AD_NETWORKS_WHITELIST, function(i, item) {
114 if (item.name === name) 104 if (item.name === name)
115 result = item; 105 result = item;
116 }); 106 });
117 return result; 107 return result;
118 } 108 }
119 109
120 /** 110 /**
121 * @constructor 111 * @constructor
122 */ 112 */
123 function AdView(node) { 113 function AdView(adviewNode) {
124 this.node_ = node; 114 this.adviewNode_ = adviewNode;
125 var shadowRoot = node.webkitCreateShadowRoot(); 115 this.browserPluginNode_ = this.createBrowserPluginNode_();
116 var shadowRoot = this.adviewNode_.webkitCreateShadowRoot();
117 shadowRoot.appendChild(this.browserPluginNode_);
126 118
127 this.objectNode_ = document.createElement('object'); 119 this.setupCustomAttributes_();
128 this.objectNode_.type = 'application/browser-plugin'; 120 this.setupAdviewNodeObservers_();
121 this.setupAdviewNodeMethods_();
122 this.setupAdviewNodeProperties_();
123 this.setupAdviewNodeEvents_();
124 this.setupBrowserPluginNodeObservers_();
125 }
126
127 /**
128 * @private
129 */
130 AdView.prototype.createBrowserPluginNode_ = function() {
131 var browserPluginNode = document.createElement('object');
132 browserPluginNode.type = 'application/browser-plugin';
129 // The <object> node fills in the <adview> container. 133 // The <object> node fills in the <adview> container.
130 this.objectNode_.style.width = '100%'; 134 browserPluginNode.style.width = '100%';
131 this.objectNode_.style.height = '100%'; 135 browserPluginNode.style.height = '100%';
132 forEach(AD_VIEW_ATTRIBUTES, function(i, attributeName) { 136 forEach(AD_VIEW_ATTRIBUTES, function(i, attributeName) {
133 // Only copy attributes that have been assigned values, rather than copying 137 // Only copy attributes that have been assigned values, rather than copying
134 // a series of undefined attributes to BrowserPlugin. 138 // a series of undefined attributes to BrowserPlugin.
135 if (this.node_.hasAttribute(attributeName)) { 139 if (this.adviewNode_.hasAttribute(attributeName)) {
136 this.objectNode_.setAttribute( 140 browserPluginNode.setAttribute(
137 attributeName, this.node_.getAttribute(attributeName)); 141 attributeName, this.adviewNode_.getAttribute(attributeName));
138 } 142 }
139 }, this); 143 }, this);
140 144
145 return browserPluginNode;
146 }
147
148 /**
149 * @private
150 */
151 AdView.prototype.setupCustomAttributes_ = function() {
141 forEach(AD_VIEW_CUSTOM_ATTRIBUTES, function(i, attributeInfo) { 152 forEach(AD_VIEW_CUSTOM_ATTRIBUTES, function(i, attributeInfo) {
142 if (attributeInfo.onInit) { 153 if (attributeInfo.onMutation) {
143 attributeInfo.onInit(this); 154 attributeInfo.onMutation(this);
144 } 155 }
145 }, this); 156 }, this);
157 }
146 158
147 shadowRoot.appendChild(this.objectNode_); 159 /**
148 160 * @private
149 // this.objectNode_[apiMethod] are not necessarily defined immediately after 161 */
150 // the shadow object is appended to the shadow root. 162 AdView.prototype.setupAdviewNodeMethods_ = function() {
163 // this.browserPluginNode_[apiMethod] are not necessarily defined immediately
164 // after the shadow object is appended to the shadow root.
151 var self = this; 165 var self = this;
152 forEach(AD_VIEW_API_METHODS, function(i, apiMethod) { 166 forEach(AD_VIEW_API_METHODS, function(i, apiMethod) {
153 node[apiMethod] = function(var_args) { 167 self.adviewNode_[apiMethod] = function(var_args) {
154 return self.objectNode_[apiMethod].apply(self.objectNode_, arguments); 168 return self.browserPluginNode_[apiMethod].apply(
169 self.browserPluginNode_, arguments);
155 }; 170 };
156 }, this); 171 }, this);
172 }
157 173
174 /**
175 * @private
176 */
177 AdView.prototype.setupAdviewNodeObservers_ = function() {
158 // Map attribute modifications on the <adview> tag to property changes in 178 // Map attribute modifications on the <adview> tag to property changes in
159 // the underlying <object> node. 179 // the underlying <object> node.
160 var handleMutation = function(i, mutation) { 180 var handleMutation = function(i, mutation) {
161 this.handleMutation_(mutation); 181 this.handleAdviewAttributeMutation_(mutation);
162 }.bind(this); 182 }.bind(this);
163 var observer = new WebKitMutationObserver(function(mutations) { 183 var observer = new WebKitMutationObserver(function(mutations) {
164 forEach(mutations, handleMutation); 184 forEach(mutations, handleMutation);
165 }); 185 });
166 observer.observe( 186 observer.observe(
167 this.node_, 187 this.adviewNode_,
168 {attributes: true, attributeFilter: AD_VIEW_ATTRIBUTES}); 188 {attributes: true, attributeFilter: AD_VIEW_ATTRIBUTES});
169 189
170 var handleObjectMutation = function(i, mutation) { 190 this.setupAdviewNodeCustomObservers_();
171 this.handleObjectMutation_(mutation); 191 }
172 }.bind(this);
173 var objectObserver = new WebKitMutationObserver(function(mutations) {
174 forEach(mutations, handleObjectMutation);
175 });
176 objectObserver.observe(
177 this.objectNode_,
178 {attributes: true, attributeFilter: AD_VIEW_ATTRIBUTES});
179 192
180 // Map custom attribute modifications on the <adview> tag to property changes 193 /**
181 // in the underlying <object> node. 194 * @private
182 var handleCustomMutation = function(i, mutation) { 195 */
183 this.handleCustomMutation_(mutation); 196 AdView.prototype.setupAdviewNodeCustomObservers_ = function() {
197 var handleMutation = function(i, mutation) {
198 this.handleAdviewCustomAttributeMutation_(mutation);
184 }.bind(this); 199 }.bind(this);
185 var observer = new WebKitMutationObserver(function(mutations) { 200 var observer = new WebKitMutationObserver(function(mutations) {
186 forEach(mutations, handleCustomMutation); 201 forEach(mutations, handleMutation);
187 }); 202 });
188 var customAttributeNames = 203 var customAttributeNames =
189 AD_VIEW_CUSTOM_ATTRIBUTES.map(function(item) { return item.name; }); 204 AD_VIEW_CUSTOM_ATTRIBUTES.map(function(item) { return item.name; });
190 observer.observe( 205 observer.observe(
191 this.node_, 206 this.adviewNode_,
192 {attributes: true, attributeFilter: customAttributeNames}); 207 {attributes: true, attributeFilter: customAttributeNames});
208 }
193 209
194 var objectNode = this.objectNode_; 210 /**
211 * @private
212 */
213 AdView.prototype.setupBrowserPluginNodeObservers_ = function() {
214 var handleMutation = function(i, mutation) {
215 this.handleBrowserPluginAttributeMutation_(mutation);
216 }.bind(this);
217 var objectObserver = new WebKitMutationObserver(function(mutations) {
218 forEach(mutations, handleMutation);
219 });
220 objectObserver.observe(
221 this.browserPluginNode_,
222 {attributes: true, attributeFilter: AD_VIEW_ATTRIBUTES});
223 }
224
225 /**
226 * @private
227 */
228 AdView.prototype.setupAdviewNodeProperties_ = function() {
229 var browserPluginNode = this.browserPluginNode_;
195 // Expose getters and setters for the attributes. 230 // Expose getters and setters for the attributes.
196 forEach(AD_VIEW_ATTRIBUTES, function(i, attributeName) { 231 forEach(AD_VIEW_ATTRIBUTES, function(i, attributeName) {
197 Object.defineProperty(this.node_, attributeName, { 232 Object.defineProperty(this.adviewNode_, attributeName, {
198 get: function() { 233 get: function() {
199 return objectNode[attributeName]; 234 return browserPluginNode[attributeName];
200 }, 235 },
201 set: function(value) { 236 set: function(value) {
202 objectNode[attributeName] = value; 237 browserPluginNode[attributeName] = value;
203 }, 238 },
204 enumerable: true 239 enumerable: true
205 }); 240 });
206 }, this); 241 }, this);
207 242
243 // Expose getters and setters for the custom attributes.
244 var adviewNode = this.adviewNode_;
245 forEach(AD_VIEW_CUSTOM_ATTRIBUTES, function(i, attributeInfo) {
246 if (attributeInfo.isProperty()) {
247 var attributeName = attributeInfo.name;
248 Object.defineProperty(this.adviewNode_, attributeName, {
249 get: function() {
250 return adviewNode.getAttribute(attributeName);
251 },
252 set: function(value) {
253 adviewNode.setAttribute(attributeName, value);
254 },
255 enumerable: true
256 });
257 }
258 }, this);
259
260 this.setupAdviewContentWindowProperty_();
261 }
262
263 /**
264 * @private
265 */
266 AdView.prototype.setupAdviewContentWindowProperty_ = function() {
267 var browserPluginNode = this.browserPluginNode_;
208 // We cannot use {writable: true} property descriptor because we want dynamic 268 // We cannot use {writable: true} property descriptor because we want dynamic
209 // getter value. 269 // getter value.
210 Object.defineProperty(this.node_, 'contentWindow', { 270 Object.defineProperty(this.adviewNode_, 'contentWindow', {
211 get: function() { 271 get: function() {
212 // TODO(fsamuel): This is a workaround to enable 272 // TODO(fsamuel): This is a workaround to enable
213 // contentWindow.postMessage until http://crbug.com/152006 is fixed. 273 // contentWindow.postMessage until http://crbug.com/152006 is fixed.
214 if (objectNode.contentWindow) 274 if (browserPluginNode.contentWindow)
215 return objectNode.contentWindow.self; 275 return browserPluginNode.contentWindow.self;
216 console.error('contentWindow is not available at this time. ' + 276 console.error('contentWindow is not available at this time. ' +
217 'It will become available when the page has finished loading.'); 277 'It will become available when the page has finished loading.');
218 }, 278 },
219 // No setter. 279 // No setter.
220 enumerable: true 280 enumerable: true
221 }); 281 });
222
223 for (var eventName in AD_VIEW_EVENTS) {
224 this.setupEvent_(eventName, AD_VIEW_EVENTS[eventName]);
225 }
226 } 282 }
227 283
228 /** 284 /**
229 * @private 285 * @private
230 */ 286 */
231 AdView.prototype.handleMutation_ = function(mutation) { 287 AdView.prototype.handleAdviewAttributeMutation_ = function(mutation) {
232 // This observer monitors mutations to attributes of the <adview> and 288 // This observer monitors mutations to attributes of the <adview> and
233 // updates the BrowserPlugin properties accordingly. In turn, updating 289 // updates the BrowserPlugin properties accordingly. In turn, updating
234 // a BrowserPlugin property will update the corresponding BrowserPlugin 290 // a BrowserPlugin property will update the corresponding BrowserPlugin
235 // attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more 291 // attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more
236 // details. 292 // details.
237 this.objectNode_[mutation.attributeName] = 293 this.browserPluginNode_[mutation.attributeName] =
238 this.node_.getAttribute(mutation.attributeName); 294 this.adviewNode_.getAttribute(mutation.attributeName);
239 }; 295 };
240 296
241 /** 297 /**
242 * @private 298 * @private
243 */ 299 */
244 AdView.prototype.handleCustomMutation_ = function(mutation) { 300 AdView.prototype.handleAdviewCustomAttributeMutation_ = function(mutation) {
245 // This observer monitors mutations to attributes of the <adview> and
246 // updates the BrowserPlugin properties accordingly. In turn, updating
247 // a BrowserPlugin property will update the corresponding BrowserPlugin
248 // attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more
249 // details.
250 forEach(AD_VIEW_CUSTOM_ATTRIBUTES, function(i, item) { 301 forEach(AD_VIEW_CUSTOM_ATTRIBUTES, function(i, item) {
251 if (mutation.attributeName.toUpperCase() == item.name.toUpperCase()) { 302 if (mutation.attributeName.toUpperCase() == item.name.toUpperCase()) {
252 if (item.onMutation) { 303 if (item.onMutation) {
253 item.onMutation.bind(item)(this, mutation); 304 item.onMutation.bind(item)(this, mutation);
254 } 305 }
255 } 306 }
256 }, this); 307 }, this);
257 }; 308 };
258 309
259 /** 310 /**
260 * @private 311 * @private
261 */ 312 */
262 AdView.prototype.handleObjectMutation_ = function(mutation) { 313 AdView.prototype.handleBrowserPluginAttributeMutation_ = function(mutation) {
263 // This observer monitors mutations to attributes of the BrowserPlugin and 314 // This observer monitors mutations to attributes of the BrowserPlugin and
264 // updates the <adview> attributes accordingly. 315 // updates the <adview> attributes accordingly.
265 if (!this.objectNode_.hasAttribute(mutation.attributeName)) { 316 if (!this.browserPluginNode_.hasAttribute(mutation.attributeName)) {
266 // If an attribute is removed from the BrowserPlugin, then remove it 317 // If an attribute is removed from the BrowserPlugin, then remove it
267 // from the <adview> as well. 318 // from the <adview> as well.
268 this.node_.removeAttribute(mutation.attributeName); 319 this.adviewNode_.removeAttribute(mutation.attributeName);
269 } else { 320 } else {
270 // Update the <adview> attribute to match the BrowserPlugin attribute. 321 // Update the <adview> attribute to match the BrowserPlugin attribute.
271 // Note: Calling setAttribute on <adview> will trigger its mutation 322 // Note: Calling setAttribute on <adview> will trigger its mutation
272 // observer which will then propagate that attribute to BrowserPlugin. In 323 // observer which will then propagate that attribute to BrowserPlugin. In
273 // cases where we permit assigning a BrowserPlugin attribute the same value 324 // cases where we permit assigning a BrowserPlugin attribute the same value
274 // again (such as navigation when crashed), this could end up in an infinite 325 // again (such as navigation when crashed), this could end up in an infinite
275 // loop. Thus, we avoid this loop by only updating the <adview> attribute 326 // loop. Thus, we avoid this loop by only updating the <adview> attribute
276 // if the BrowserPlugin attributes differs from it. 327 // if the BrowserPlugin attributes differs from it.
277 var oldValue = this.node_.getAttribute(mutation.attributeName); 328 var oldValue = this.adviewNode_.getAttribute(mutation.attributeName);
278 var newValue = this.objectNode_.getAttribute(mutation.attributeName); 329 var newValue = this.browserPluginNode_.getAttribute(mutation.attributeName);
279 if (newValue != oldValue) { 330 if (newValue != oldValue) {
280 this.node_.setAttribute(mutation.attributeName, newValue); 331 this.adviewNode_.setAttribute(mutation.attributeName, newValue);
281 } 332 }
282 } 333 }
283 }; 334 };
284 335
285 /** 336 /**
286 * @private 337 * @private
287 */ 338 */
339 AdView.prototype.navigateToUrl_ = function(url) {
340 var newValue = url;
341 var oldValue = this.browserPluginNode_.hasAttribute('src') ?
342 this.browserPluginNode_.getAttribute('src') :
343 null;
344
345 if (newValue === oldValue)
346 return;
347
348 if (url != null) {
349 // Note: setAttribute does not work as intended here.
350 //this.browserPluginNode_.setAttribute('src', url);
351 this.browserPluginNode_['src'] = url;
352 if (allowCustomAdNetworks()) {
353 this.adviewNode_.setAttribute('src', url);
354 }
355 }
356 else {
357 this.browserPluginNode_.removeAttribute('src');
358 if (allowCustomAdNetworks()) {
359 this.adviewNode_.removeAttribute('src');
360 }
361 }
362 }
363
364 /**
365 * @public
366 */
367 AdView.prototype.handleAdNetworkMutation = function(mutation) {
368 if (this.adviewNode_.hasAttribute('ad-network')) {
369 var value = this.adviewNode_.getAttribute('ad-network');
370 var item = getAdNetworkInfo(value);
371 if (item) {
372 this.navigateToUrl_(item.url);
373 }
374 else {
375 if (allowCustomAdNetworks()) {
376 console.log('The ad-network "' + value + '" is not recognized, ' +
377 'but custom ad-networks are enabled.');
378 var newValue = value;
379 var oldValue = (mutation ? mutation.oldValue : undefined);
380 if (newValue !== oldValue) {
381 this.navigateToUrl_('');
382 }
383 }
384 else {
385 // Ignore the new attribute value and set it to empty string.
386 // Avoid infinite loop by checking for empty string as new value.
387 if (value != '') {
388 console.error('The ad-network "' + value + '" is not recognized.');
389 this.adviewNode_.setAttribute('ad-network', '');
390 }
391 this.navigateToUrl_('');
392 }
393 }
394 }
395 else {
396 this.navigateToUrl_('');
397 }
398 }
399
400 /**
401 * @public
402 */
403 AdView.prototype.handleSrcMutation = function(mutation) {
404 if (allowCustomAdNetworks()) {
405 if (this.adviewNode_.hasAttribute('src')) {
406 var newValue = this.adviewNode_.getAttribute('src');
407 // Note: setAttribute does not work as intended here.
408 //this.browserPluginNode_.setAttribute('src', newValue);
409 this.browserPluginNode_['src'] = newValue;
410 }
411 else {
412 // If an attribute is removed from the <adview>, then remove it
413 // from the BrowserPlugin as well.
414 this.browserPluginNode_.removeAttribute('src');
415 }
416 }
417 else {
418 if (this.adviewNode_.hasAttribute('src')) {
419 var value = this.adviewNode_.getAttribute('src');
420 // Ignore the new attribute value and set it to empty string.
421 // Avoid infinite loop by checking for empty string as new value.
422 if (value != '') {
423 console.error('Setting the "src" attribute of an <adview> ' +
424 'element is not supported. Use the "ad-network" attribute ' +
425 'instead.');
426 this.adviewNode_.setAttribute('src', '');
427 }
428 }
429 }
430 }
431
432 /**
433 * @private
434 */
435 AdView.prototype.setupAdviewNodeEvents_ = function() {
436 for (var eventName in AD_VIEW_EVENTS) {
437 this.setupEvent_(eventName, AD_VIEW_EVENTS[eventName]);
438 }
439 }
440
441 /**
442 * @private
443 */
288 AdView.prototype.setupEvent_ = function(eventname, attribs) { 444 AdView.prototype.setupEvent_ = function(eventname, attribs) {
289 var node = this.node_; 445 var adviewNode = this.adviewNode_;
290 this.objectNode_.addEventListener('-internal-' + eventname, function(e) { 446 var internalname = '-internal-' + eventname;
447 this.browserPluginNode_.addEventListener(internalname, function(e) {
291 var evt = new Event(eventname, { bubbles: true }); 448 var evt = new Event(eventname, { bubbles: true });
292 var detail = e.detail ? JSON.parse(e.detail) : {}; 449 var detail = e.detail ? JSON.parse(e.detail) : {};
293 forEach(attribs, function(i, attribName) { 450 forEach(attribs, function(i, attribName) {
294 evt[attribName] = detail[attribName]; 451 evt[attribName] = detail[attribName];
295 }); 452 });
296 node.dispatchEvent(evt); 453 adviewNode.dispatchEvent(evt);
297 }); 454 });
298 } 455 }
299 456
457 /**
458 * @public
459 */
460 AdView.prototype.dispatchEvent = function(eventname, detail) {
461 // Create event object.
462 var evt = new Event(eventname, { bubbles: true });
463 for(var item in detail) {
464 evt[item] = detail[item];
465 }
466
467 // Dispatch event.
468 this.adviewNode_.dispatchEvent(evt);
469 }
470
471
300 // 472 //
301 // Hook up <adview> tag creation in DOM. 473 // Hook up <adview> tag creation in DOM.
302 // 474 //
303 var watchForTag = require("tagWatcher").watchForTag;
304
305 window.addEventListener('DOMContentLoaded', function() { 475 window.addEventListener('DOMContentLoaded', function() {
306 watchForTag('ADVIEW', function(addedNode) { new AdView(addedNode); }); 476 watchForTag('ADVIEW', function(addedNode) { new AdView(addedNode); });
307 }); 477 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698