Skip to content

Commit 29dbff6

Browse files
committed
Merge branch 'feature/2.4.0'
2 parents b6e65b0 + bafe80d commit 29dbff6

File tree

19 files changed

+321
-45
lines changed

19 files changed

+321
-45
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ node_modules
2020

2121
**/lodash.js
2222
tests/pages/*.js
23+
tests/pages/integration.html
2324
tags/tag.min.js
2425

2526
# creds for Grunt

.travis.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ install:
99
- unzip ./ngrok.zip\?os=linux\&arch=386\&channel=stable
1010
before_script:
1111
- node tests/integration/request_recorder.js &
12-
- ./ngrok -authtoken $NGROK_AUTH -subdomain=snowplow -log=stdout 8500 > /dev/null &
12+
13+
# Create a random ngrok subdomain
14+
- export SUBDOMAIN=$RANDOM$RANDOM
15+
- ./ngrok -authtoken $NGROK_AUTH -subdomain $SUBDOMAIN -log=stdout 8500 > /dev/null &
1316
script:
1417
- grunt travis
1518
after_script:

CHANGELOG

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
Version 2.4.0 (2015-03-16)
2+
--------------------------
3+
Added ability to modify links allowing cross-domain tracking (#109)
4+
Added timing event (#320)
5+
Increased safety of document size detection (#334)
6+
Started randomly generating ngrok subdomain in integration tests (#333)
7+
Fixed Vagrant setup to use latest Peru version (#336)
8+
Stopped caching page URL and referrer URL (#337)
9+
Stopped caching PerformanceTiming context (#339)
10+
Added common contexts to link_click, change_form, and submit_form events (#340)
11+
112
Version 2.3.0 (2015-03-03)
213
-------------------------
314
Added support for sending events via POST (#168)

Gruntfile.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ module.exports = function(grunt) {
7777

7878
pkg: pkg,
7979

80+
subdomain: process.env.SUBDOMAIN,
81+
8082
lodash: {
8183
build: {
8284
dest: 'src/js/lib_managed/lodash.js',
@@ -119,6 +121,13 @@ module.exports = function(grunt) {
119121
},
120122
src: ['tags/tag.min.js'],
121123
dest: 'tags/tag.min.js'
124+
},
125+
test: {
126+
options: {
127+
'process': true
128+
},
129+
src: ['tests/pages/integration-template.html'],
130+
dest: 'tests/pages/integration.html'
122131
}
123132
},
124133

@@ -154,6 +163,7 @@ module.exports = function(grunt) {
154163
runType: 'client',
155164
config: 'tests/intern.js',
156165
suites: [
166+
'tests/nonfunctional/helpers.js',
157167
'tests/nonfunctional/in_queue.js',
158168
'tests/nonfunctional/proxies.js'
159169
]
@@ -250,6 +260,6 @@ module.exports = function(grunt) {
250260
grunt.registerTask('publish', 'Upload to S3 and invalidate Cloudfront (full semantic version only)', ['upload_setup', 'lodash', 'browserify:main', 'concat:deploy', 'min:deploy', 's3:not_pinned', 'cloudfront:not_pinned']);
251261
grunt.registerTask('publish-pinned', 'Upload to S3 and invalidate Cloudfront (full semantic version and semantic major version)', ['upload_setup', 'lodash', 'browserify:main', 'concat:deploy', 'min:deploy', 's3', 'cloudfront']);
252262
grunt.registerTask('test', 'Intern tests', ['browserify:test', 'intern']);
253-
grunt.registerTask('travis', 'Intern tests for Travis CI', ['lodash','browserify:test','intern']);
263+
grunt.registerTask('travis', 'Intern tests for Travis CI', ['lodash','concat:test', 'browserify:test','intern']);
254264
grunt.registerTask('tags', 'Minifiy the Snowplow invocation tag', ['min:tag', 'concat:tag']);
255265
}

examples/ads/async.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ <h1>Asynchronous ad tracking examples for snowplow.js</h1>
3838
;(function(p,l,o,w,i,n,g){if(!p[i]){p.GlobalSnowplowNamespace=p.GlobalSnowplowNamespace||[];
3939
p.GlobalSnowplowNamespace.push(i);p[i]=function(){(p[i].q=p[i].q||[]).push(arguments)
4040
};p[i].q=p[i].q||[];n=l.createElement(o);g=l.getElementsByTagName(o)[0];n.async=1;
41-
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.3.0/sp.js","adTracker"));
41+
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.0/sp.js","adTracker"));
4242

4343
window.adTracker('newTracker', rnd, 'd3rkrsqld9gmqf.cloudfront.net', {
4444
'encodeBase64': false
@@ -110,7 +110,7 @@ <h1>Asynchronous ad tracking examples for snowplow.js</h1>
110110
;(function(p,l,o,w,i,n,g){if(!p[i]){p.GlobalSnowplowNamespace=p.GlobalSnowplowNamespace||[];
111111
p.GlobalSnowplowNamespace.push(i);p[i]=function(){(p[i].q=p[i].q||[]).push(arguments)
112112
};p[i].q=p[i].q||[];n=l.createElement(o);g=l.getElementsByTagName(o)[0];n.async=1;
113-
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.3.0/sp.js","adTracker"));
113+
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.0/sp.js","adTracker"));
114114

115115
window.adTracker('newTracker', rnd, 'd3rkrsqld9gmqf.cloudfront.net', {
116116
'encodeBase64': false
@@ -141,7 +141,7 @@ <h1>Asynchronous ad tracking examples for snowplow.js</h1>
141141
;(function(p,l,o,w,i,n,g){if(!p[i]){p.GlobalSnowplowNamespace=p.GlobalSnowplowNamespace||[];
142142
p.GlobalSnowplowNamespace.push(i);p[i]=function(){(p[i].q=p[i].q||[]).push(arguments)
143143
};p[i].q=p[i].q||[];n=l.createElement(o);g=l.getElementsByTagName(o)[0];n.async=1;
144-
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.3.0/sp.js","adTracker"));
144+
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.0/sp.js","adTracker"));
145145

146146
window.adTracker('newTracker', rnd, 'd3rkrsqld9gmqf.cloudfront.net', {
147147
'encodeBase64': false

examples/web/async-large.html

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,13 @@
2323
;(function(p,l,o,w,i,n,g){if(!p[i]){p.GlobalSnowplowNamespace=p.GlobalSnowplowNamespace||[];
2424
p.GlobalSnowplowNamespace.push(i);p[i]=function(){(p[i].q=p[i].q||[]).push(arguments)
2525
};p[i].q=p[i].q||[];n=l.createElement(o);g=l.getElementsByTagName(o)[0];n.async=1;
26-
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.3.0/sp.js","snowplow_1"));
26+
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.0/sp.js","snowplow_1"));
2727

2828
window.snowplow_1('newTracker', 'cf', 'd3rkrsqld9gmqf.cloudfront.net', { // Initialise a tracker
2929
encodeBase64: false, // Default is true
3030
appId: 'CFe23a', // Site ID can be anything you want. Set it if you're tracking more than one site in this account
3131
platform: 'mob',
32+
crossDomainLinker: function (link) {return link.id === 'legal'}, // Add duid and timestamp to the link with id "legal"
3233
contexts: {
3334
performanceTiming: true
3435
}
@@ -81,7 +82,7 @@
8182
;(function(p,l,o,w,i,n,g){if(!p[i]){p.GlobalSnowplowNamespace=p.GlobalSnowplowNamespace||[];
8283
p.GlobalSnowplowNamespace.push(i);p[i]=function(){(p[i].q=p[i].q||[]).push(arguments)
8384
};p[i].q=p[i].q||[];n=l.createElement(o);g=l.getElementsByTagName(o)[0];n.async=1;
84-
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.3.0/sp.js","snowplow_2"));
85+
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.0/sp.js","snowplow_2"));
8586

8687
window.snowplow_2('newTracker', 'cf', 'd3rkrsqld9gmqf.cloudfront.net', { // Initialise a tracker
8788
encodeBase64: false, // Default is true
@@ -243,7 +244,8 @@ <h2>This shows how two users can simultaneously use Snowplow on the same page wi
243244
</p>
244245
<p>
245246
Middle click the links to trigger link click tracking:<br>
246-
<a href=http://en.wikipedia.org/wiki/Main_Page id=legal target="_blank" class="link out">Link</a>
247+
<!-- crossDomain functionality correctly alters a link with a multiple question marks and a fragment -->
248+
<a href=http://en.wikipedia.org/wiki/Main_Page?a=b?c#fragment id=legal target="_blank" class="link out">Link</a>
247249
<br>
248250
<a href=http://en.wikipedia.org/wiki/Main_Page id=illegal class="class barred">Link ignored by one user</a>
249251
</p>

examples/web/async-medium.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
;(function(p,l,o,w,i,n,g){if(!p[i]){p.GlobalSnowplowNamespace=p.GlobalSnowplowNamespace||[];
2525
p.GlobalSnowplowNamespace.push(i);p[i]=function(){(p[i].q=p[i].q||[]).push(arguments)
2626
};p[i].q=p[i].q||[];n=l.createElement(o);g=l.getElementsByTagName(o)[0];n.async=1;
27-
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.3.0/sp.js","new_name_here"));
27+
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.0/sp.js","new_name_here"));
2828

2929
window.new_name_here('newTracker', 'cf', 'd3rkrsqld9gmqf.cloudfront.net', {
3030
encodeBase64: false,

examples/web/async-small.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
;(function(p,l,o,w,i,n,g){if(!p[i]){p.GlobalSnowplowNamespace=p.GlobalSnowplowNamespace||[];
2424
p.GlobalSnowplowNamespace.push(i);p[i]=function(){(p[i].q=p[i].q||[]).push(arguments)
2525
};p[i].q=p[i].q||[];n=l.createElement(o);g=l.getElementsByTagName(o)[0];n.async=1;
26-
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.3.0/sp.js","snowplow"));
26+
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.0/sp.js","snowplow"));
2727

2828
window.snowplow('newTracker', 'cf', 'd3rkrsqld9gmqf.cloudfront.net', { // Initialise a tracker
2929
encodeBase64: false, // Default is true

examples/web/sync.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
<!-- Snowplow starts plowing -->
2121
<script type="text/javascript">
22-
var spSrc = ('https:' == document.location.protocol ? 'https' : 'http') + '://d1fc8wv8zag5ca.cloudfront.net/2.3.0/sp.js';
22+
var spSrc = ('https:' == document.location.protocol ? 'https' : 'http') + '://d1fc8wv8zag5ca.cloudfront.net/2.4.0/sp.js';
2323
document.write(unescape("%3Cscript src='" + spSrc + "' type='text/javascript'%3E%3C/script%3E"));
2424
</script>
2525
<script type="text/javascript">

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "snowplow-tracker",
3-
"version": "2.3.0",
3+
"version": "2.4.0",
44
"devDependencies": {
55
"JSON": "~1.0.0",
66
"browser-cookie-lite": "~0.3.1",

src/js/forms.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ var lodash = require('./lib_managed/lodash'),
4141
*
4242
* @param object core The tracker core
4343
* @param string trackerId Unique identifier for the tracker instance, used to mark tracked elements
44+
* @param function contextAdder Function to add common contexts like PerformanceTiming to all events
4445
* @return object formTrackingManager instance
4546
*/
46-
object.getFormTrackingManager = function (core, trackerId) {
47+
object.getFormTrackingManager = function (core, trackerId, contextAdder) {
4748

4849
// Tag names of mutable elements inside a form
4950
var innerElementTags = ['textarea', 'input', 'select'];
@@ -123,7 +124,7 @@ object.getFormTrackingManager = function (core, trackerId) {
123124
var elt = e.target;
124125
var type = elt.nodeName.toUpperCase() === 'INPUT' ? elt.type : null;
125126
var value = (elt.type === 'checkbox' && !elt.checked) ? null : elt.value;
126-
core.trackFormChange(getParentFormName(elt), getFormElementName(elt), elt.nodeName, type, lodash.map(elt.classList), value, context);
127+
core.trackFormChange(getParentFormName(elt), getFormElementName(elt), elt.nodeName, type, lodash.map(elt.classList), value, contextAdder(context));
127128
};
128129
}
129130

@@ -134,7 +135,7 @@ object.getFormTrackingManager = function (core, trackerId) {
134135
return function (e) {
135136
var elt = e.target;
136137
var innerElements = getInnerFormElements(elt);
137-
core.trackFormSubmission(getFormElementName(elt), lodash.map(elt.classList), innerElements, context);
138+
core.trackFormSubmission(getFormElementName(elt), lodash.map(elt.classList), innerElements, contextAdder(context));
138139
};
139140
}
140141

src/js/lib/detectors.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,12 @@
170170
*/
171171
object.detectDocumentSize = function() {
172172
var de = documentAlias.documentElement, // Alias
173-
be = documentAlias.body;
173+
be = documentAlias.body,
174+
175+
// document.body may not have rendered, so check whether be.offsetHeight is null
176+
bodyHeight = be ? Math.max(be.offsetHeight, be.scrollHeight) : 0;
174177
var w = Math.max(de.clientWidth, de.offsetWidth, de.scrollWidth);
175-
var h = Math.max(de.clientHeight, de.offsetHeight, de.scrollHeight,
176-
be.offsetHeight, be.scrollHeight);
178+
var h = Math.max(de.clientHeight, de.offsetHeight, de.scrollHeight, bodyHeight);
177179
return isNaN(w) || isNaN(h) ? '' : w + 'x' + h;
178180
};
179181

src/js/lib/helpers.js

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,16 @@
8181
return domain;
8282
};
8383

84-
/*
85-
* Get page referrer
84+
/**
85+
* Get page referrer. In the case of a single-page app,
86+
* if the URL changes without the page reloading, pass
87+
* in the old URL. It will be returned unless overriden
88+
* by a "refer(r)er" parameter in the querystring.
89+
*
90+
* @param string oldLocation Optional.
91+
* @return string The referrer
8692
*/
87-
object.getReferrer = function () {
93+
object.getReferrer = function (oldLocation) {
8894

8995
var referrer = '';
9096

@@ -96,6 +102,11 @@
96102
return fromQs;
97103
}
98104

105+
// In the case of a single-page app, return the old URL
106+
if (oldLocation) {
107+
return oldLocation;
108+
}
109+
99110
try {
100111
referrer = window.top.document.referrer;
101112
} catch (e) {
@@ -207,4 +218,40 @@
207218
}
208219
}
209220

221+
/**
222+
* Add a name-value pair to the querystring of a URL
223+
*
224+
* @param string url URL to decorate
225+
* @param string name Name of the querystring pair
226+
* @param string value Value of the querystring pair
227+
*/
228+
object.decorateQuerystring = function (url, name, value) {
229+
var initialQsParams = name + '=' + value;
230+
var hashSplit = url.split('#');
231+
var qsSplit = hashSplit[0].split('?');
232+
var beforeQuerystring = qsSplit.shift();
233+
// Necessary because a querystring may contain multiple question marks
234+
var querystring = qsSplit.join('?');
235+
if (!querystring) {
236+
querystring = initialQsParams;
237+
} else {
238+
// Whether this is the first time the link has been decorated
239+
var initialDecoration = true;
240+
var qsFields = querystring.split('&');
241+
for (var i=0; i<qsFields.length; i++) {
242+
if (qsFields[i].substr(0, name.length + 1) === name + '=') {
243+
initialDecoration = false;
244+
qsFields[i] = initialQsParams;
245+
querystring = qsFields.join('&');
246+
break;
247+
}
248+
}
249+
if (initialDecoration) {
250+
querystring = initialQsParams + '&' + querystring;
251+
}
252+
}
253+
hashSplit[0] = beforeQuerystring + '?' + querystring;
254+
return hashSplit.join('#');
255+
}
256+
210257
}());

src/js/links.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ var lodash = require('./lib_managed/lodash'),
4141
*
4242
* @param object core The tracker core
4343
* @param string trackerId Unique identifier for the tracker instance, used to mark tracked links
44+
* @param function contextAdder Function to add common contexts like PerformanceTiming to all events
4445
* @return object linkTrackingManager instance
4546
*/
46-
object.getLinkTrackingManager = function (core, trackerId) {
47+
object.getLinkTrackingManager = function (core, trackerId, contextAdder) {
4748

4849
// Filter function used to determine whether clicks on a link should be tracked
4950
var linkTrackingFilter,
@@ -96,7 +97,7 @@ object.getLinkTrackingManager = function (core, trackerId) {
9697

9798
// decodeUrl %xx
9899
sourceHref = unescape(sourceHref);
99-
core.trackLinkClick(sourceHref, elementId, elementClasses, elementTarget, elementContent, context);
100+
core.trackLinkClick(sourceHref, elementId, elementClasses, elementTarget, elementContent, contextAdder(context));
100101
}
101102
}
102103
}

0 commit comments

Comments
 (0)