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