mirror of
https://github.com/reddit-archive/reddit.git
synced 2026-04-27 03:00:12 -04:00
Add google tag manager
Also supports do not track (DNT) as a means of opt out. NOTES: - GMT must be double iframed to not leak the referrer. - since the page can be CDN cached we need to check DNT client side. - we do not respect the value of DNT in IE10 since they default it to on (against the spec). - GMT is disabled unless the DNT feature flag is enabled.
This commit is contained in:
@@ -180,6 +180,8 @@ googleanalytics_gold =
|
||||
googleanalytics_sample_rate_gold = 100
|
||||
# secret used for signing information on the above tracking pixels
|
||||
tracking_secret = abcdefghijklmnopqrstuvwxyz0123456789
|
||||
# google tag manager container id
|
||||
googletagmanager =
|
||||
|
||||
#### Wiki Pages
|
||||
wiki_page_content_policy = contentpolicy
|
||||
|
||||
@@ -170,6 +170,9 @@ def make_map(config):
|
||||
|
||||
mc("/newsletter", controller="newsletter", action="newsletter")
|
||||
|
||||
mc("/gtm/jail", controller="googletagmanager", action="jail")
|
||||
mc("/gtm", controller="googletagmanager", action="gtm")
|
||||
|
||||
mc('/oembed', controller='oembed', action='oembed')
|
||||
|
||||
mc('/about/sidebar', controller='front', action='sidebar')
|
||||
|
||||
@@ -69,6 +69,7 @@ def load_controllers():
|
||||
from awards import AwardsController
|
||||
from errorlog import ErrorlogController
|
||||
from newsletter import NewsletterController
|
||||
from googletagmanager import GoogleTagManagerController
|
||||
from promotecontroller import PromoteController
|
||||
from promotecontroller import SponsorController
|
||||
from promotecontroller import PromoteApiController
|
||||
|
||||
49
r2/r2/controllers/googletagmanager.py
Normal file
49
r2/r2/controllers/googletagmanager.py
Normal file
@@ -0,0 +1,49 @@
|
||||
# The contents of this file are subject to the Common Public Attribution
|
||||
# License Version 1.0. (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
|
||||
# License Version 1.1, but Sections 14 and 15 have been added to cover use of
|
||||
# software over a computer network and provide for limited attribution for the
|
||||
# Original Developer. In addition, Exhibit A has been modified to be consistent
|
||||
# with Exhibit B.
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
|
||||
# the specific language governing rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is reddit.
|
||||
#
|
||||
# The Original Developer is the Initial Developer. The Initial Developer of
|
||||
# the Original Code is reddit Inc.
|
||||
#
|
||||
# All portions of the code written by reddit are Copyright (c) 2006-2015 reddit
|
||||
# Inc. All Rights Reserved.
|
||||
###############################################################################
|
||||
|
||||
from pylons import app_globals as g
|
||||
from pylons import tmpl_context as c
|
||||
from pylons import request
|
||||
|
||||
from r2.controllers.reddit_base import MinimalController
|
||||
from r2.lib.pages import (
|
||||
GoogleTagManagerJail,
|
||||
GoogleTagManager,
|
||||
)
|
||||
|
||||
|
||||
class GoogleTagManagerController(MinimalController):
|
||||
def pre(self):
|
||||
if request.host != g.media_domain:
|
||||
# don't serve up untrusted content except on our
|
||||
# specifically untrusted domain
|
||||
self.abort404()
|
||||
|
||||
MinimalController.pre(self)
|
||||
|
||||
c.allow_framing = True
|
||||
|
||||
def GET_jail(self):
|
||||
return GoogleTagManagerJail().render()
|
||||
|
||||
def GET_gtm(self):
|
||||
return GoogleTagManager().render()
|
||||
@@ -405,12 +405,29 @@ module = {}
|
||||
|
||||
catch_errors = "try {{ {content} }} catch (err) {{ r.sendError('Error running module', '{name}', ':', err.toString()) }}"
|
||||
|
||||
|
||||
module["gtm-jail"] = Module("gtm-jail.js",
|
||||
"lib/json2.js",
|
||||
"custom-event.js",
|
||||
"frames.js",
|
||||
"google-tag-manager/gtm-jail-listener.js",
|
||||
)
|
||||
|
||||
|
||||
module["gtm"] = Module("gtm.js",
|
||||
"lib/json2.js",
|
||||
"custom-event.js",
|
||||
"frames.js",
|
||||
"google-tag-manager/gtm-listener.js",
|
||||
)
|
||||
|
||||
|
||||
module["reddit-embed-base"] = Module("reddit-embed-base.js",
|
||||
"lib/es5-shim.js",
|
||||
"lib/json2.js",
|
||||
"embed/custom-event.js",
|
||||
"custom-event.js",
|
||||
"frames.js",
|
||||
"embed/utils.js",
|
||||
"embed/post-message.js",
|
||||
"embed/pixel-tracking.js",
|
||||
)
|
||||
|
||||
@@ -438,6 +455,7 @@ module["reddit-init-base"] = LocalizedModule("reddit-init-base.js",
|
||||
"lib/bootstrap.tooltip.js",
|
||||
"lib/reddit-client-lib.js",
|
||||
"lib/jquery.cookie.js",
|
||||
"do-not-track.js",
|
||||
"bootstrap.tooltip.extension.js",
|
||||
"base.js",
|
||||
"hooks.js",
|
||||
@@ -482,11 +500,12 @@ module["reddit-init"] = LocalizedModule("reddit-init.js",
|
||||
module["reddit"] = LocalizedModule("reddit.js",
|
||||
"lib/jquery.url.js",
|
||||
"lib/backbone-1.0.0.js",
|
||||
"embed/custom-event.js",
|
||||
"custom-event.js",
|
||||
"frames.js",
|
||||
"embed/utils.js",
|
||||
"embed/post-message.js",
|
||||
"embed/pixel-tracking.js",
|
||||
"embed/comment-embed.js",
|
||||
"google-tag-manager/gtm.js",
|
||||
"timings.js",
|
||||
"templates.js",
|
||||
"scrollupdater.js",
|
||||
|
||||
@@ -269,6 +269,7 @@ class Reddit(Templated):
|
||||
self.loginbox = loginbox
|
||||
self.show_sidebar = show_sidebar
|
||||
self.space_compress = space_compress
|
||||
self.dnt_enabled = feature.is_enabled("do_not_track")
|
||||
# instantiate a footer
|
||||
self.header = header
|
||||
self.footer = RedditFooter() if footer else None
|
||||
@@ -5409,6 +5410,14 @@ class PolicyPage(BoringPage):
|
||||
return toolbars
|
||||
|
||||
|
||||
class GoogleTagManagerJail(Templated):
|
||||
pass
|
||||
|
||||
|
||||
class GoogleTagManager(Templated):
|
||||
pass
|
||||
|
||||
|
||||
class Newsletter(BoringPage):
|
||||
extra_page_classes = ['newsletter']
|
||||
|
||||
|
||||
11
r2/r2/public/static/js/do-not-track.js
Normal file
11
r2/r2/public/static/js/do-not-track.js
Normal file
@@ -0,0 +1,11 @@
|
||||
!(function(global, undefined) {
|
||||
var RE_IE_VERSION = /(?:\b(?:MS)?IE\s+|\bTrident\/7\.0;.*\s+rv:)(\d+(?:\.?\d+)?)/i;
|
||||
var uaMatches = navigator.userAgent.match(RE_IE_VERSION);
|
||||
var ieVersion = uaMatches && uaMatches[1] && parseFloat(uaMatches[1]);
|
||||
var doNotTrack = navigator.doNotTrack ||
|
||||
global.doNotTrack ||
|
||||
navigator.msDoNotTrack;
|
||||
|
||||
global.DO_NOT_TRACK = /^(yes|1)$/i.test(doNotTrack) && ieVersion !== 10;
|
||||
|
||||
})(this);
|
||||
@@ -63,7 +63,8 @@
|
||||
return;
|
||||
}
|
||||
|
||||
App.addPostMessageOrigin(embed.getAttribute('data-embed-media'));
|
||||
r.frames.addPostMessageOrigin(embed.getAttribute('data-embed-media'));
|
||||
r.frames.listen('embed');
|
||||
|
||||
iframe.height = iframe.style.height = 0;
|
||||
iframe.width = iframe.style.width = '100%';
|
||||
@@ -82,12 +83,12 @@
|
||||
iframe.style.boxSizing = 'border-box';
|
||||
iframe.src = getEmbedUrl(commentUrl, embed);
|
||||
|
||||
App.receiveMessageOnce(iframe, 'ping', function(e) {
|
||||
r.frames.receiveMessageOnce(iframe, 'ping.embed', function(e) {
|
||||
embed.parentNode.removeChild(embed);
|
||||
iframe.style.display = 'block';
|
||||
|
||||
callback(e);
|
||||
App.postMessage(iframe.contentWindow, 'pong', {
|
||||
r.frames.postMessage(iframe.contentWindow, 'pong.embed', {
|
||||
type: embed.getAttribute('data-embed-parent') === 'true' ?
|
||||
'comment_and_parent' : 'comment',
|
||||
location: location,
|
||||
@@ -95,7 +96,7 @@
|
||||
});
|
||||
});
|
||||
|
||||
var resizer = App.receiveMessage(iframe, 'resize', function(e) {
|
||||
var resizer = r.frames.receiveMessage(iframe, 'resize.embed', function(e) {
|
||||
if (!iframe.parentNode) {
|
||||
resizer.off();
|
||||
|
||||
@@ -115,4 +116,4 @@
|
||||
|
||||
App.init();
|
||||
|
||||
})((window.rembeddit = window.rembeddit || {}), this);
|
||||
})((window.rembeddit = window.rembeddit || {}), window.r, this);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
;(function(App, window, undefined) {
|
||||
;(function(App, r, window, undefined) {
|
||||
App.VERSION = '0.1';
|
||||
|
||||
var RE_HOST = /^https?:\/\/([^\/|?]+).*/;
|
||||
@@ -6,16 +6,18 @@
|
||||
var thing = config.thing;
|
||||
|
||||
if (document.referrer && document.referrer.match(RE_HOST)) {
|
||||
App.addPostMessageOrigin(RegExp.$1);
|
||||
r.frames.addPostMessageOrigin(RegExp.$1);
|
||||
}
|
||||
|
||||
r.frames.listen('embed');
|
||||
|
||||
function checkHeight() {
|
||||
var height = document.body.clientHeight;
|
||||
|
||||
if (height && App.height !== height) {
|
||||
App.height = height;
|
||||
|
||||
App.postMessage(window.parent, 'resize', height, '*');
|
||||
r.frames.postMessage(window.parent, 'resize.embed', height, { targetOrigin: '*' });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +86,7 @@
|
||||
|
||||
setInterval(checkHeight, 100);
|
||||
|
||||
App.receiveMessage(window.parent, 'pong', function(e) {
|
||||
r.frames.receiveMessage(window.parent, 'pong.embed', function(e) {
|
||||
var type = e.detail.type;
|
||||
var options = e.detail.options;
|
||||
var location = e.detail.location;
|
||||
@@ -159,8 +161,8 @@
|
||||
|
||||
});
|
||||
|
||||
App.postMessage(window.parent, 'ping', {
|
||||
r.frames.postMessage(window.parent, 'ping.embed', {
|
||||
config: config,
|
||||
});
|
||||
|
||||
})((window.rembeddit = window.rembeddit || {}), this);
|
||||
})((window.rembeddit = window.rembeddit || {}), window.r, this);
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
;(function(App, window, undefined) {
|
||||
var WILDCARD = '*';
|
||||
var ALLOW_WILDCARD = '.*';
|
||||
var RE_WILDCARD = /\*/;
|
||||
|
||||
var allowedOrigins = [ALLOW_WILDCARD];
|
||||
var re_postMessageAllowedOrigin = compileOriginRegExp(allowedOrigins);
|
||||
|
||||
function receiveMessage(e) {
|
||||
if (!re_postMessageAllowedOrigin.test(e.origin) && e.origin !== 'null') {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var message = JSON.parse(e.data);
|
||||
var customEvent = new CustomEvent(message.type, {detail: message.data});
|
||||
|
||||
customEvent.source = e.source;
|
||||
|
||||
window.dispatchEvent(customEvent);
|
||||
} catch (x) {}
|
||||
}
|
||||
|
||||
function compileOriginRegExp(origins) {
|
||||
return new RegExp('^http(s)?:\\/\\/' + origins.join('|'), 'i');
|
||||
}
|
||||
|
||||
function isWildcard(origin) {
|
||||
return RE_WILDCARD.test(origin);
|
||||
}
|
||||
|
||||
App.utils.extend(App, {
|
||||
|
||||
postMessage: function(target, type, data, options) {
|
||||
type += '.postMessage';
|
||||
|
||||
var defaults = {
|
||||
targetOrigin: WILDCARD,
|
||||
delay: 100
|
||||
};
|
||||
|
||||
options = App.utils.extend({}, defaults, options);
|
||||
|
||||
target.postMessage(JSON.stringify({type: type, data: data}), options.targetOrigin);
|
||||
},
|
||||
|
||||
receiveMessage: function(source, type, callback, context) {
|
||||
if (typeof source === 'string') {
|
||||
context = callback;
|
||||
callback = type;
|
||||
type = source;
|
||||
source = null;
|
||||
}
|
||||
|
||||
type += '.postMessage';
|
||||
context = context || this;
|
||||
|
||||
var scoped = function(e) {
|
||||
if (source &&
|
||||
source !== e.source &&
|
||||
source.contentWindow !== e.source) {
|
||||
return;
|
||||
}
|
||||
|
||||
callback.apply(context, arguments);
|
||||
}
|
||||
|
||||
window.addEventListener(type, scoped);
|
||||
|
||||
return {
|
||||
off: function () { window.removeEventListener(type, scoped); }
|
||||
};
|
||||
},
|
||||
|
||||
receiveMessageOnce: function(source, type, callback, context) {
|
||||
var listener = App.receiveMessage(source, type, function() {
|
||||
callback && callback.apply(this, arguments);
|
||||
|
||||
listener.off();
|
||||
}, context);
|
||||
|
||||
return listener;
|
||||
},
|
||||
|
||||
addPostMessageOrigin: function(origin) {
|
||||
if (isWildcard(origin)) {
|
||||
allowedOrigins = [ALLOW_WILDCARD];
|
||||
} else if (allowedOrigins.indexOf(origin) === -1) {
|
||||
App.removePostMessageOrigin(ALLOW_WILDCARD);
|
||||
|
||||
allowedOrigins.push(origin);
|
||||
|
||||
re_postMessageAllowedOrigin = compileOriginRegExp(allowedOrigins);
|
||||
}
|
||||
},
|
||||
|
||||
removePostMessageOrigin: function(origin) {
|
||||
var index = allowedOrigins.indexOf(origin);
|
||||
|
||||
if (index !== -1) {
|
||||
allowedOrigins.splice(index, 1);
|
||||
|
||||
re_postMessageAllowedOrigin = compileOriginRegExp(allowedOrigins);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if ('addEventListener' in window) {
|
||||
window.addEventListener('message', receiveMessage, false);
|
||||
} else if ('attachEvent' in window) {
|
||||
window.attachEvent('onmessage', receiveMessage)
|
||||
}
|
||||
|
||||
})((window.rembeddit = window.rembeddit || {}), this);
|
||||
@@ -3,40 +3,6 @@
|
||||
|
||||
App.utils = App.utils || {};
|
||||
|
||||
App.utils.extend = function(obj) {
|
||||
if (typeof obj !== 'object') {
|
||||
return obj;
|
||||
}
|
||||
|
||||
var source, prop;
|
||||
|
||||
for (var i = 1, length = arguments.length; i < length; i++) {
|
||||
source = arguments[i];
|
||||
for (prop in source) {
|
||||
if (hasOwnProperty.call(source, prop)) {
|
||||
obj[prop] = source[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
App.utils.find = function(array, test) {
|
||||
var found;
|
||||
|
||||
for (var i = 0; l = array.length, i < l; i++) {
|
||||
var item = array[i];
|
||||
|
||||
if (test(item, i, array)) {
|
||||
found = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
};
|
||||
|
||||
// http://stackoverflow.com/a/8809472/704286
|
||||
App.utils.uuid = function() {
|
||||
var d = new Date().getTime();
|
||||
|
||||
246
r2/r2/public/static/js/frames.js
Normal file
246
r2/r2/public/static/js/frames.js
Normal file
@@ -0,0 +1,246 @@
|
||||
;(function(r, global, undefined) {
|
||||
'use strict';
|
||||
|
||||
var ALLOW_WILDCARD = '.*';
|
||||
var DEFAULT_MESSAGE_NAMESPACE = '.postMessage';
|
||||
var DEFAULT_POSTMESSAGE_OPTIONS = {
|
||||
targetOrigin: '*',
|
||||
};
|
||||
|
||||
var allowedOrigins = [ALLOW_WILDCARD];
|
||||
var re_postMessageAllowedOrigin = compileOriginRegExp(allowedOrigins);
|
||||
var messageNamespaces = [DEFAULT_MESSAGE_NAMESPACE];
|
||||
var re_messageNamespaces = compileNamespaceRegExp(messageNamespaces);
|
||||
var proxies = {};
|
||||
var listening = false;
|
||||
|
||||
function receiveMessage(e) {
|
||||
if (e.origin !== location.origin &&
|
||||
!re_postMessageAllowedOrigin.test(e.origin)
|
||||
&& e.origin !== 'null') {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var message = JSON.parse(e.data);
|
||||
var type = message.type;
|
||||
|
||||
// Namespace doesn't match, ignore
|
||||
if (!re_messageNamespaces.test(type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var namespace = type.split('.', 2)[1];
|
||||
|
||||
if (proxies[namespace]) {
|
||||
var proxyWith = proxies[namespace];
|
||||
|
||||
r.frames.postMessage(proxyWith.target, type, message.data, message.options);
|
||||
}
|
||||
|
||||
var customEvent = new CustomEvent(type, {detail: message.data});
|
||||
customEvent.source = e.source;
|
||||
|
||||
global.dispatchEvent(customEvent);
|
||||
} catch (x) {}
|
||||
}
|
||||
|
||||
function _addEventListener(type, handler, useCapture) {
|
||||
if ('addEventListener' in global) {
|
||||
global.addEventListener(type, handler, useCapture);
|
||||
} else if ('attachEvent' in global) {
|
||||
global.attachEvent('on' + type, handler);
|
||||
}
|
||||
}
|
||||
|
||||
function _removeEventListener(type, handler, useCapture) {
|
||||
if ('removeEventListener' in global) {
|
||||
global.removeEventListener(type, handler);
|
||||
} else if ('detachEvent' in global) {
|
||||
global.attachEvent('on' + type, handler);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function compileOriginRegExp(origins) {
|
||||
return new RegExp('^http(s)?:\\/\\/' + origins.join('|') + '$', 'i');
|
||||
}
|
||||
|
||||
function compileNamespaceRegExp(namespaces) {
|
||||
return new RegExp('\\.(?:' + namespaces.join('|') + ')$')
|
||||
}
|
||||
|
||||
function isWildcard(origin) {
|
||||
return /\*/.test(origin);
|
||||
}
|
||||
|
||||
|
||||
/** @module frames */
|
||||
/* @example
|
||||
* // parent window
|
||||
* // frames.listen('dfp')
|
||||
* // frames.receiveMessageOnce('init.dfp', callback)
|
||||
* @example
|
||||
* // iframe
|
||||
* // frames.postMessage(window.parent, 'init.dfp', data);
|
||||
*/
|
||||
var frames = r.frames = {
|
||||
/*
|
||||
* Send a message to another window.
|
||||
* param {Window} target The frame to deliver the message to.
|
||||
* param {String} type The message type. (if it doesn't include a namespace the default namespace will be used)
|
||||
* param {Object} data The data to send.
|
||||
* param {Object} options The `postMessage` options.
|
||||
* param {String} options.targetOrigin Specifies what the origin of otherWindow must be for the event to be dispatched.
|
||||
*/
|
||||
postMessage: function (target, type, data, options) {
|
||||
if (!/\..+$/.test(type)) {
|
||||
type += DEFAULT_MESSAGE_NAMESPACE;
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
for (var key in DEFAULT_POSTMESSAGE_OPTIONS) {
|
||||
if (!options.hasOwnProperty(key)) {
|
||||
options[key] = DEFAULT_POSTMESSAGE_OPTIONS[key];
|
||||
}
|
||||
}
|
||||
|
||||
target.postMessage(JSON.stringify({type: type, data: data, options: options}), options.targetOrigin);
|
||||
},
|
||||
|
||||
/*
|
||||
* Receive a message from another window.
|
||||
* param {Window} [source] The frame to that send the message.
|
||||
* param {String} type The message type. (if it doesn't include a namespace the default namespace will be used)
|
||||
* param {Function} callback The callback to invoke upon retrieval.
|
||||
* param {Object} [context=this] The context the callback is invoked with.
|
||||
* returns {Object} The listener.
|
||||
*/
|
||||
receiveMessage: function (source, type, callback, context) {
|
||||
if (typeof source === 'string') {
|
||||
context = callback;
|
||||
callback = type;
|
||||
type = source;
|
||||
source = null;
|
||||
}
|
||||
|
||||
context = context || this;
|
||||
|
||||
var scoped = function(e) {
|
||||
if (source &&
|
||||
source !== e.source &&
|
||||
source.contentWindow !== e.source) {
|
||||
return;
|
||||
}
|
||||
|
||||
callback.apply(context, arguments);
|
||||
};
|
||||
|
||||
_addEventListener(type, scoped);
|
||||
|
||||
return {
|
||||
off: function() { _removeEventListener(type, scoped); }
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
* Proxies messages on a namespace from a frame to a specified target.
|
||||
* param {String} namespace The namespace to proxy.
|
||||
* target {Window} [source] The frame to proxy messages to.
|
||||
*/
|
||||
proxy: function(namespace, target) {
|
||||
this.listen(namespace);
|
||||
|
||||
proxies[namespace] = {
|
||||
target: target,
|
||||
};
|
||||
},
|
||||
|
||||
/*
|
||||
* Receive a message from another window once.
|
||||
* param {Window} [source] The frame to that send the message.
|
||||
* param {String} type The message type. (if it doesn't include a namespace the default namespace will be used)
|
||||
* param {Function} callback The callback to invoke upon retrieval.
|
||||
* param {Object} [context=this] The context the callback is invoked with.
|
||||
* returns {Object} The listener.
|
||||
*/
|
||||
receiveMessageOnce: function (source, type, callback, context) {
|
||||
var listener = frames.receiveMessage(source, type, function() {
|
||||
callback && callback.apply(this, arguments);
|
||||
|
||||
listener.off();
|
||||
}, context);
|
||||
|
||||
return listener;
|
||||
},
|
||||
|
||||
/*
|
||||
* Adds an allowed origin to be listened to.
|
||||
* param {String} origin The origin to be added.
|
||||
*/
|
||||
addPostMessageOrigin: function (origin) {
|
||||
if (isWildcard(origin)) {
|
||||
allowedOrigins = [ALLOW_WILDCARD];
|
||||
} else if (allowedOrigins.indexOf(origin) === -1) {
|
||||
frames.removePostMessageOrigin(ALLOW_WILDCARD);
|
||||
|
||||
allowedOrigins.push(origin);
|
||||
|
||||
re_postMessageAllowedOrigin = compileOriginRegExp(allowedOrigins);
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Removes an origin from the list of those listened to.
|
||||
* param {String} origin The origin to be removed.
|
||||
*/
|
||||
removePostMessageOrigin: function (origin) {
|
||||
var index = allowedOrigins.indexOf(origin);
|
||||
|
||||
if (index !== -1) {
|
||||
allowedOrigins.splice(index, 1);
|
||||
|
||||
re_postMessageAllowedOrigin = compileOriginRegExp(allowedOrigins);
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Listens to messages on of the specified namespace.
|
||||
* param {String} namespace The namespace to be listened to.
|
||||
*/
|
||||
listen: function (namespace) {
|
||||
if (messageNamespaces.indexOf(namespace) === -1) {
|
||||
messageNamespaces.push(namespace);
|
||||
re_messageNamespaces = compileNamespaceRegExp(messageNamespaces);
|
||||
}
|
||||
|
||||
if (!listening) {
|
||||
_addEventListener('message', receiveMessage);
|
||||
|
||||
listening = true;
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Stops listening to messages on of the specified namespace.
|
||||
* param {String} namespace The namespace to stop listening to.
|
||||
*/
|
||||
stopListening: function (namespace) {
|
||||
var index = messageNamespaces.indexOf(namespace);
|
||||
|
||||
if (index !== -1) {
|
||||
messageNamespaces.splice(index, 1);
|
||||
|
||||
if (messageNamespaces.length) {
|
||||
re_messageNamespaces = compileNamespaceRegExp(messageNamespaces);
|
||||
} else {
|
||||
_removeEventListener('message', receiveMessage);
|
||||
listening = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
})((this.r = this.r || {}), this);
|
||||
@@ -0,0 +1,5 @@
|
||||
;(function(global, r, undefined) {
|
||||
var jail = document.getElementById('jail');
|
||||
|
||||
r.frames.proxy('gtm', jail.contentWindow);
|
||||
})(this, this.r);
|
||||
14
r2/r2/public/static/js/google-tag-manager/gtm-listener.js
Normal file
14
r2/r2/public/static/js/google-tag-manager/gtm-listener.js
Normal file
@@ -0,0 +1,14 @@
|
||||
;(function(gtm, global, r, undefined) {
|
||||
var dataLayer = global.googleTagManager = global.googleTagManager || [];
|
||||
|
||||
r.frames.listen('gtm');
|
||||
|
||||
r.frames.receiveMessage('data.gtm', function(e) {
|
||||
dataLayer.push(e.detail);
|
||||
});
|
||||
|
||||
r.frames.receiveMessage('event.gtm', function(e) {
|
||||
dataLayer.push(e.detail);
|
||||
});
|
||||
|
||||
})((this.gtm = this.gtm || {}), this, this.r);
|
||||
22
r2/r2/public/static/js/google-tag-manager/gtm.js
Normal file
22
r2/r2/public/static/js/google-tag-manager/gtm.js
Normal file
@@ -0,0 +1,22 @@
|
||||
;(function(r, global, undefined) {
|
||||
var jail = document.getElementById('gtm-jail');
|
||||
|
||||
r.gtm = {
|
||||
|
||||
trigger: function(eventName, payload) {
|
||||
if (payload) {
|
||||
this.set(payload);
|
||||
}
|
||||
|
||||
r.frames.postMessage(jail.contentWindow, 'event.gtm', {
|
||||
event: eventName,
|
||||
});
|
||||
},
|
||||
|
||||
set: function(data) {
|
||||
r.frames.postMessage(jail.contentWindow, 'data.gtm', data);
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
})((this.r = this.r || {}), this);
|
||||
26
r2/r2/public/static/js/jail.js
Normal file
26
r2/r2/public/static/js/jail.js
Normal file
@@ -0,0 +1,26 @@
|
||||
;(function(r, global, undefined) {
|
||||
var jail = document.getElementById('gtm-sandbox');
|
||||
|
||||
r.jail = {
|
||||
|
||||
postMessage: function(id, eventName, data) {
|
||||
|
||||
},
|
||||
|
||||
trigger: function(eventName, payload) {
|
||||
if (payload) {
|
||||
this.set(payload);
|
||||
}
|
||||
|
||||
r.frames.postMessage(sandbox.contentWindow, 'event.gtm', {
|
||||
event: eventName,
|
||||
});
|
||||
},
|
||||
|
||||
set: function(data) {
|
||||
r.frames.postMessage(sandbox.contentWindow, 'data.gtm', data);
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
})((this.r = this.r || {}), this);
|
||||
@@ -26,7 +26,7 @@
|
||||
from r2.models import Link, Comment, Subreddit
|
||||
from r2.lib import tracking
|
||||
%>
|
||||
<%namespace file="utils.html" import="js_setup, googleanalytics, classes"/>
|
||||
<%namespace file="utils.html" import="js_setup, googleanalytics, googletagmanager, classes"/>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="${c.lang}"
|
||||
xml:lang="${c.lang}">
|
||||
<head>
|
||||
@@ -57,6 +57,7 @@
|
||||
</head>
|
||||
|
||||
<body ${classes(*thing.page_classes())}>
|
||||
${googletagmanager()}
|
||||
${self.bodyContent()}
|
||||
${self.javascript_bottom()}
|
||||
</body>
|
||||
|
||||
51
r2/r2/templates/googletagmanager.html
Normal file
51
r2/r2/templates/googletagmanager.html
Normal file
@@ -0,0 +1,51 @@
|
||||
## The contents of this file are subject to the Common Public Attribution
|
||||
## License Version 1.0. (the "License"); you may not use this file except in
|
||||
## compliance with the License. You may obtain a copy of the License at
|
||||
## http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
|
||||
## License Version 1.1, but Sections 14 and 15 have been added to cover use of
|
||||
## software over a computer network and provide for limited attribution for the
|
||||
## Original Developer. In addition, Exhibit A has been modified to be
|
||||
## consistent with Exhibit B.
|
||||
##
|
||||
## Software distributed under the License is distributed on an "AS IS" basis,
|
||||
## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
|
||||
## the specific language governing rights and limitations under the License.
|
||||
##
|
||||
## The Original Code is reddit.
|
||||
##
|
||||
## The Original Developer is the Initial Developer. The Initial Developer of
|
||||
## the Original Code is reddit Inc.
|
||||
##
|
||||
## All portions of the code written by reddit are Copyright (c) 2006-2014
|
||||
## reddit Inc. All Rights Reserved.
|
||||
###############################################################################
|
||||
|
||||
<%!
|
||||
from r2.lib.filters import scriptsafe_dumps, unsafe
|
||||
from r2.lib import js
|
||||
%>
|
||||
|
||||
<%namespace file="utils.html" import="googletagmanager"/>
|
||||
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<meta name="referrer" content="no-referrer">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
${unsafe(js.use('gtm'))}
|
||||
<noscript>
|
||||
<iframe src="//www.googletagmanager.com/ns.html?id=${g.googletagmanager}"
|
||||
height="0" width="0" style="display:none;visibility:hidden"></iframe>
|
||||
</noscript>
|
||||
<script>
|
||||
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
||||
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
||||
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
||||
'//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
||||
})(window,document,'script','googleTagManager',${scriptsafe_dumps(g.googletagmanager)});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
39
r2/r2/templates/googletagmanagerjail.html
Normal file
39
r2/r2/templates/googletagmanagerjail.html
Normal file
@@ -0,0 +1,39 @@
|
||||
## The contents of this file are subject to the Common Public Attribution
|
||||
## License Version 1.0. (the "License"); you may not use this file except in
|
||||
## compliance with the License. You may obtain a copy of the License at
|
||||
## http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
|
||||
## License Version 1.1, but Sections 14 and 15 have been added to cover use of
|
||||
## software over a computer network and provide for limited attribution for the
|
||||
## Original Developer. In addition, Exhibit A has been modified to be
|
||||
## consistent with Exhibit B.
|
||||
##
|
||||
## Software distributed under the License is distributed on an "AS IS" basis,
|
||||
## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
|
||||
## the specific language governing rights and limitations under the License.
|
||||
##
|
||||
## The Original Code is reddit.
|
||||
##
|
||||
## The Original Developer is the Initial Developer. The Initial Developer of
|
||||
## the Original Code is reddit Inc.
|
||||
##
|
||||
## All portions of the code written by reddit are Copyright (c) 2006-2014
|
||||
## reddit Inc. All Rights Reserved.
|
||||
###############################################################################
|
||||
|
||||
<%!
|
||||
from r2.lib.filters import unsafe
|
||||
from r2.lib import js
|
||||
%>
|
||||
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<meta name="referrer" content="no-referrer">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<iframe id="jail" src="/gtm" style="display:none;" referrer="no-referrer">
|
||||
${unsafe(js.use('gtm-jail'))}
|
||||
</body>
|
||||
</html>
|
||||
@@ -25,7 +25,7 @@
|
||||
from datetime import datetime
|
||||
|
||||
from r2.lib import tracking
|
||||
from r2.lib.filters import spaceCompress, unsafe, safemarkdown, jssafe
|
||||
from r2.lib.filters import spaceCompress, unsafe, safemarkdown, jssafe, scriptsafe_dumps
|
||||
from r2.lib.template_helpers import (
|
||||
add_sr,
|
||||
html_datetime,
|
||||
@@ -445,6 +445,23 @@ ${unsafe(txt)}
|
||||
</script>
|
||||
</%def>
|
||||
|
||||
<%def name="googletagmanager()">
|
||||
%if g.googletagmanager and thing.site_tracking and thing.dnt_enabled:
|
||||
<script>
|
||||
if (!window.DO_NOT_TRACK) {
|
||||
var frame = document.createElement('iframe');
|
||||
|
||||
frame.style.display = 'none';
|
||||
frame.referrer = 'no-referrer';
|
||||
frame.id = 'gtm-jail';
|
||||
frame.src = '//' + ${scriptsafe_dumps(g.media_domain)} + '/gtm/jail';
|
||||
|
||||
document.body.appendChild(frame);
|
||||
}
|
||||
</script>
|
||||
%endif
|
||||
</%def>
|
||||
|
||||
<%def name="googleanalytics(uitype, is_gold_page=False)">
|
||||
%if (g.googleanalytics or g.googleanalytics_gold) and thing.site_tracking:
|
||||
<script type="text/javascript">
|
||||
|
||||
Reference in New Issue
Block a user