OLD | NEW |
---|---|
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 | |
benwells
2013/04/02 00:49:45
Nit: remove extra blank line
rpaquay
2013/04/02 16:44:47
Done.
| |
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 |
benwells
2013/04/02 00:49:45
Nit: remove extra blank line
rpaquay
2013/04/02 16:44:47
Done.
| |
20 /** | |
21 * Define "allowCustomAdNetworks" function such that it returns "true" if the | |
22 * "adViewCustom" module was injected. This is so that the | |
benwells
2013/04/02 00:49:45
Is there some precedent for this style of multi li
rpaquay
2013/04/02 16:44:47
There are a few files in this same folder using mu
| |
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 |
benwells
2013/04/02 00:49:45
Nit: remove extra blank line
rpaquay
2013/04/02 16:44:47
Done.
| |
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', |
benwells
2013/04/02 00:49:45
Is there any reason to lump the refactor and the t
rpaquay
2013/04/02 16:44:47
Most of the refactor was initiated as a result of
| |
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 }); |
OLD | NEW |