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

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

Issue 12463015: Enable <adview> tag for packaged apps. (Closed) Base URL: https://git.chromium.org/chromium/src.git@master
Patch Set: Merge fix. 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
(Empty)
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
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 adViewCustom = require('adViewCustom');
14 var chrome = requireNative('chrome').GetChrome();
15 var forEach = require('utils').forEach;
16 var watchForTag = require('tagWatcher').watchForTag;
17
18
19 var allowCustomAdNetworks = (function(allow){
20 return function() { return Boolean(allow); }
21 })(adViewCustom ? adViewCustom.enabled : false);
22
23
24 // List of attribute names to "blindly" sync between <adview> tag and internal
25 // browser plugin.
26 var AD_VIEW_ATTRIBUTES = [
27 'name',
28 ];
29
30 // List of custom attributes (and their behavior)
31 //
32 // name: attribute name.
33 // onInit(adview): callback invoked when the <adview> element is created.
34 // onMutate(adview, mutation): callback invoked when attribute is mutated.
35 var AD_VIEW_CUSTOM_ATTRIBUTES = [
36 {
37 'name': "ad-network",
38 'onInit': function(adview) {
39 if (adview.node_.hasAttribute(this.name)) {
40 var value = adview.node_.getAttribute(this.name);
41 var item = getAdNetworkInfo(value);
42 if (item) {
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 }
54 },
55 {
56 'name': "src",
57 'onInit': function(adview) {
58 if (allowCustomAdNetworks()) {
59 if (adview.node_.hasAttribute(this.name)) {
60 var newValue = adview.node_.getAttribute(this.name);
61 adview.objectNode_.setAttribute("src", newValue);
62 }
63 }
64 },
65 'onMutation': function(adview, mutation) {
66 if (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 }
80 }
81 ];
82
83 // List of api methods. These are forwarded to the browser plugin.
84 var AD_VIEW_API_METHODS = [
85 // Empty for now.
86 ];
87
88 // List of events to blindly forward from the browser plugin to the <adview>.
89 var AD_VIEW_EVENTS = {
90 'loadcommit' : [],
91 'sizechanged': ['oldHeight', 'oldWidth', 'newHeight', 'newWidth'],
92 };
93
94 // List of supported ad-networks.
95 //
96 // name: identifier of the ad-network, corresponding to a valid value
97 // of the "ad-network" attribute of an <adview> element.
98 // url: url to navigate to when initially displaying the <adview>.
99 // origin: origin of urls the <adview> is allowed navigate to.
100 var AD_VIEW_AD_NETWORKS_WHITELIST = [
101 {
102 'name': 'admob',
103 'url': 'https://admob-sdk.doubleclick.net/chromeapps',
104 'origin': 'https://double.net'
105 },
106 ];
107
108 //
109 // Return the whitelisted ad-network entry named |name|.
110 //
111 function getAdNetworkInfo(name) {
112 var result = null;
113 forEach(AD_VIEW_AD_NETWORKS_WHITELIST, function(i, item) {
114 if (item.name === name)
115 result = item;
116 });
117 return result;
118 }
119
120 /**
121 * @constructor
122 */
123 function AdView(node) {
124 this.node_ = node;
125 var shadowRoot = node.webkitCreateShadowRoot();
126
127 this.objectNode_ = document.createElement('object');
128 this.objectNode_.type = 'application/browser-plugin';
129 // The <object> node fills in the <adview> container.
130 this.objectNode_.style.width = '100%';
131 this.objectNode_.style.height = '100%';
132 forEach(AD_VIEW_ATTRIBUTES, function(i, attributeName) {
133 // Only copy attributes that have been assigned values, rather than copying
134 // a series of undefined attributes to BrowserPlugin.
135 if (this.node_.hasAttribute(attributeName)) {
136 this.objectNode_.setAttribute(
137 attributeName, this.node_.getAttribute(attributeName));
138 }
139 }, this);
140
141 forEach(AD_VIEW_CUSTOM_ATTRIBUTES, function(i, attributeInfo) {
142 if (attributeInfo.onInit) {
143 attributeInfo.onInit(this);
144 }
145 }, this);
146
147 shadowRoot.appendChild(this.objectNode_);
148
149 // this.objectNode_[apiMethod] are not necessarily defined immediately after
150 // the shadow object is appended to the shadow root.
151 var self = this;
152 forEach(AD_VIEW_API_METHODS, function(i, apiMethod) {
153 node[apiMethod] = function(var_args) {
154 return self.objectNode_[apiMethod].apply(self.objectNode_, arguments);
155 };
156 }, this);
157
158 // Map attribute modifications on the <adview> tag to property changes in
159 // the underlying <object> node.
160 var handleMutation = function(i, mutation) {
161 this.handleMutation_(mutation);
162 }.bind(this);
163 var observer = new WebKitMutationObserver(function(mutations) {
164 forEach(mutations, handleMutation);
165 });
166 observer.observe(
167 this.node_,
168 {attributes: true, attributeFilter: AD_VIEW_ATTRIBUTES});
169
170 var handleObjectMutation = function(i, mutation) {
171 this.handleObjectMutation_(mutation);
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
180 // Map custom attribute modifications on the <adview> tag to property changes
181 // in the underlying <object> node.
182 var handleCustomMutation = function(i, mutation) {
183 this.handleCustomMutation_(mutation);
184 }.bind(this);
185 var observer = new WebKitMutationObserver(function(mutations) {
186 forEach(mutations, handleCustomMutation);
187 });
188 var customAttributeNames =
189 AD_VIEW_CUSTOM_ATTRIBUTES.map(function(item) { return item.name; });
190 observer.observe(
191 this.node_,
192 {attributes: true, attributeFilter: customAttributeNames});
193
194 var objectNode = this.objectNode_;
195 // Expose getters and setters for the attributes.
196 forEach(AD_VIEW_ATTRIBUTES, function(i, attributeName) {
197 Object.defineProperty(this.node_, attributeName, {
198 get: function() {
199 return objectNode[attributeName];
200 },
201 set: function(value) {
202 objectNode[attributeName] = value;
203 },
204 enumerable: true
205 });
206 }, this);
207
208 // We cannot use {writable: true} property descriptor because we want dynamic
209 // getter value.
210 Object.defineProperty(this.node_, 'contentWindow', {
211 get: function() {
212 // TODO(fsamuel): This is a workaround to enable
213 // contentWindow.postMessage until http://crbug.com/152006 is fixed.
214 if (objectNode.contentWindow)
215 return objectNode.contentWindow.self;
216 console.error('contentWindow is not available at this time. ' +
217 'It will become available when the page has finished loading.');
218 },
219 // No setter.
220 enumerable: true
221 });
222
223 for (var eventName in AD_VIEW_EVENTS) {
224 this.setupEvent_(eventName, AD_VIEW_EVENTS[eventName]);
225 }
226 }
227
228 /**
229 * @private
230 */
231 AdView.prototype.handleMutation_ = function(mutation) {
232 // This observer monitors mutations to attributes of the <adview> and
233 // updates the BrowserPlugin properties accordingly. In turn, updating
234 // a BrowserPlugin property will update the corresponding BrowserPlugin
235 // attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more
236 // details.
237 this.objectNode_[mutation.attributeName] =
238 this.node_.getAttribute(mutation.attributeName);
239 };
240
241 /**
242 * @private
243 */
244 AdView.prototype.handleCustomMutation_ = 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) {
251 if (mutation.attributeName.toUpperCase() == item.name.toUpperCase()) {
252 if (item.onMutation) {
253 item.onMutation.bind(item)(this, mutation);
254 }
255 }
256 }, this);
257 };
258
259 /**
260 * @private
261 */
262 AdView.prototype.handleObjectMutation_ = function(mutation) {
263 // This observer monitors mutations to attributes of the BrowserPlugin and
264 // updates the <adview> attributes accordingly.
265 if (!this.objectNode_.hasAttribute(mutation.attributeName)) {
266 // If an attribute is removed from the BrowserPlugin, then remove it
267 // from the <adview> as well.
268 this.node_.removeAttribute(mutation.attributeName);
269 } else {
270 // Update the <adview> attribute to match the BrowserPlugin attribute.
271 // Note: Calling setAttribute on <adview> will trigger its mutation
272 // observer which will then propagate that attribute to BrowserPlugin. In
273 // 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
275 // loop. Thus, we avoid this loop by only updating the <adview> attribute
276 // if the BrowserPlugin attributes differs from it.
277 var oldValue = this.node_.getAttribute(mutation.attributeName);
278 var newValue = this.objectNode_.getAttribute(mutation.attributeName);
279 if (newValue != oldValue) {
280 this.node_.setAttribute(mutation.attributeName, newValue);
281 }
282 }
283 };
284
285 /**
286 * @private
287 */
288 AdView.prototype.setupEvent_ = function(eventname, attribs) {
289 var node = this.node_;
290 this.objectNode_.addEventListener('-internal-' + eventname, function(e) {
291 var evt = new Event(eventname, { bubbles: true });
292 var detail = e.detail ? JSON.parse(e.detail) : {};
293 forEach(attribs, function(i, attribName) {
294 evt[attribName] = detail[attribName];
295 });
296 node.dispatchEvent(evt);
297 });
298 }
299
300 //
301 // Hook up <adview> tag creation in DOM.
302 //
303 var watchForTag = require("tagWatcher").watchForTag;
304
305 window.addEventListener('DOMContentLoaded', function() {
306 watchForTag('ADVIEW', function(addedNode) { new AdView(addedNode); });
307 });
OLDNEW
« no previous file with comments | « chrome/renderer/extensions/dispatcher.cc ('k') | chrome/renderer/resources/extensions/ad_view_custom.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698