Skip to content

Commit d39543e

Browse files
phillipjitaloacasas
authored andcommittedJan 30, 2017
tools,doc: add Google Analytics tracking.
Adds Google Analytics tracking script to all doc pages when `DOCS_ANALYTICS` is set when running `make`: ```bash $ DOCS_ANALYTICS=<GOOGLE ANALYTICS ID> make ``` By default (when `DOCS_ANALYTICS` is not set), no tracking scripts are included. It respects "Do Not Track" settings end users might have in their browser. Also changes make target `doc-upload` from depending on the `$(TARBALL)` target, to only depend on `doc` directly. PR-URL: #6601 Reviewed-By: Johan Bergström <bugs@bergstroem.nu> Reviewed-By: Rod Vagg <rod@vagg.org> Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
1 parent 7dff6aa commit d39543e

File tree

6 files changed

+109
-6
lines changed

6 files changed

+109
-6
lines changed
 

‎Makefile

+8-2
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,11 @@ test-v8 test-v8-intl test-v8-benchmarks test-v8-all:
300300
"$ git clone https://github.com/nodejs/node.git"
301301
endif
302302

303+
# Google Analytics ID used for tracking API docs page views, empty
304+
# DOCS_ANALYTICS means no tracking scripts will be included in the
305+
# generated .html files
306+
DOCS_ANALYTICS ?=
307+
303308
apidoc_sources = $(wildcard doc/api/*.md)
304309
apidocs_html = $(apidoc_dirs) $(apiassets) $(addprefix out/,$(apidoc_sources:.md=.html))
305310
apidocs_json = $(apidoc_dirs) $(apiassets) $(addprefix out/,$(apidoc_sources:.md=.json))
@@ -333,7 +338,8 @@ out/doc/api/%.json: doc/api/%.md
333338
[ -x $(NODE) ] && $(NODE) $(gen-json) || node $(gen-json)
334339

335340
# check if ./node is actually set, else use user pre-installed binary
336-
gen-html = tools/doc/generate.js --node-version=$(FULLVERSION) --format=html --template=doc/template.html $< > $@
341+
gen-html = tools/doc/generate.js --node-version=$(FULLVERSION) --format=html \
342+
--template=doc/template.html --analytics=$(DOCS_ANALYTICS) $< > $@
337343
out/doc/api/%.html: doc/api/%.md
338344
@[ -e tools/doc/node_modules/js-yaml/package.json ] || \
339345
[ -e tools/eslint/node_modules/js-yaml/package.json ] || \
@@ -587,7 +593,7 @@ ifeq ($(XZ), 0)
587593
ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/node-$(FULLVERSION).tar.xz.done"
588594
endif
589595

590-
doc-upload: tar
596+
doc-upload: doc
591597
ssh $(STAGINGSERVER) "mkdir -p nodejs/$(DISTTYPEDIR)/$(FULLVERSION)"
592598
chmod -R ug=rw-x+X,o=r+X out/doc/
593599
scp -pr out/doc/ $(STAGINGSERVER):nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/docs/

‎doc/api_assets/dnt_helper.js

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* http://schalkneethling.github.io/blog/2015/11/06/respect-user-choice-do-not-track/
3+
* https://github.com/schalkneethling/dnt-helper/blob/master/js/dnt-helper.js
4+
*
5+
* Returns true or false based on whether doNotTack is enabled. It also takes into account the
6+
* anomalies, such as !bugzilla 887703, which effect versions of Fx 31 and lower. It also handles
7+
* IE versions on Windows 7, 8 and 8.1, where the DNT implementation does not honor the spec.
8+
* @see https://bugzilla.mozilla.org/show_bug.cgi?id=1217896 for more details
9+
* @params {string} [dnt] - An optional mock doNotTrack string to ease unit testing.
10+
* @params {string} [userAgent] - An optional mock userAgent string to ease unit testing.
11+
* @returns {boolean} true if enabled else false
12+
*/
13+
function _dntEnabled(dnt, userAgent) {
14+
15+
'use strict';
16+
17+
// for old version of IE we need to use the msDoNotTrack property of navigator
18+
// on newer versions, and newer platforms, this is doNotTrack but, on the window object
19+
// Safari also exposes the property on the window object.
20+
var dntStatus = dnt || navigator.doNotTrack || window.doNotTrack || navigator.msDoNotTrack;
21+
var ua = userAgent || navigator.userAgent;
22+
23+
// List of Windows versions known to not implement DNT according to the standard.
24+
var anomalousWinVersions = ['Windows NT 6.1', 'Windows NT 6.2', 'Windows NT 6.3'];
25+
26+
var fxMatch = ua.match(/Firefox\/(\d+)/);
27+
var ieRegEx = /MSIE|Trident/i;
28+
var isIE = ieRegEx.test(ua);
29+
// Matches from Windows up to the first occurance of ; un-greedily
30+
// http://www.regexr.com/3c2el
31+
var platform = ua.match(/Windows.+?(?=;)/g);
32+
33+
// With old versions of IE, DNT did not exist so we simply return false;
34+
if (isIE && typeof Array.prototype.indexOf !== 'function') {
35+
return false;
36+
} else if (fxMatch && parseInt(fxMatch[1], 10) < 32) {
37+
// Can't say for sure if it is 1 or 0, due to Fx bug 887703
38+
dntStatus = 'Unspecified';
39+
} else if (isIE && platform && anomalousWinVersions.indexOf(platform.toString()) !== -1) {
40+
// default is on, which does not honor the specification
41+
dntStatus = 'Unspecified';
42+
} else {
43+
// sets dntStatus to Disabled or Enabled based on the value returned by the browser.
44+
// If dntStatus is undefined, it will be set to Unspecified
45+
dntStatus = { '0': 'Disabled', '1': 'Enabled' }[dntStatus] || 'Unspecified';
46+
}
47+
48+
return dntStatus === 'Enabled' ? true : false;
49+
}

‎doc/template.html

+1
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,6 @@ <h2>Table of Contents</h2>
4545
<script src="assets/sh_main.js"></script>
4646
<script src="assets/sh_javascript.min.js"></script>
4747
<script>highlight(undefined, undefined, 'pre');</script>
48+
<!-- __TRACKING__ -->
4849
</body>
4950
</html>

‎test/doctool/test-doctool-html.js

+18
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,18 @@ const testData = [
7272
'<p>I exist and am being linked to.</p>' +
7373
'<!-- [end-include:doc_inc_2.md] -->'
7474
},
75+
{
76+
file: path.join(common.fixturesDir, 'sample_document.md'),
77+
html: '<ol><li>fish</li><li><p>fish</p></li><li><p>Redfish</p></li>' +
78+
'<li>Bluefish</li></ol>',
79+
analyticsId: 'UA-67020396-1'
80+
},
7581
];
7682

7783
testData.forEach((item) => {
7884
// Normalize expected data by stripping whitespace
7985
const expected = item.html.replace(/\s/g, '');
86+
const includeAnalytics = typeof item.analyticsId !== 'undefined';
8087

8188
fs.readFile(item.file, 'utf8', common.mustCall((err, input) => {
8289
assert.ifError(err);
@@ -89,6 +96,7 @@ testData.forEach((item) => {
8996
filename: 'foo',
9097
template: 'doc/template.html',
9198
nodeVersion: process.version,
99+
analytics: item.analyticsId,
92100
},
93101
common.mustCall((err, output) => {
94102
assert.ifError(err);
@@ -97,6 +105,16 @@ testData.forEach((item) => {
97105
// Assert that the input stripped of all whitespace contains the
98106
// expected list
99107
assert.notStrictEqual(actual.indexOf(expected), -1);
108+
109+
// Testing the insertion of Google Analytics script when
110+
// an analytics id is provided. Should not be present by default
111+
if (includeAnalytics) {
112+
assert.notStrictEqual(actual.indexOf('google-analytics.com'), -1,
113+
'Google Analytics script was not present');
114+
} else {
115+
assert.strictEqual(actual.indexOf('google-analytics.com'), -1,
116+
'Google Analytics script was present');
117+
}
100118
}));
101119
}));
102120
}));

‎tools/doc/generate.js

+8-4
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,19 @@ let format = 'json';
1111
let template = null;
1212
let inputFile = null;
1313
let nodeVersion = null;
14+
let analytics = null;
1415

1516
args.forEach(function(arg) {
16-
if (!arg.match(/^--/)) {
17+
if (!arg.startsWith('--')) {
1718
inputFile = arg;
18-
} else if (arg.match(/^--format=/)) {
19+
} else if (arg.startsWith('--format=')) {
1920
format = arg.replace(/^--format=/, '');
20-
} else if (arg.match(/^--template=/)) {
21+
} else if (arg.startsWith('--template=')) {
2122
template = arg.replace(/^--template=/, '');
22-
} else if (arg.match(/^--node-version=/)) {
23+
} else if (arg.startsWith('--node-version=')) {
2324
nodeVersion = arg.replace(/^--node-version=/, '');
25+
} else if (arg.startsWith('--analytics=')) {
26+
analytics = arg.replace(/^--analytics=/, '');
2427
}
2528
});
2629

@@ -54,6 +57,7 @@ function next(er, input) {
5457
filename: inputFile,
5558
template: template,
5659
nodeVersion: nodeVersion,
60+
analytics: analytics,
5761
},
5862

5963
function(er, html) {

‎tools/doc/html.js

+25
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ function toHTML(opts, cb) {
6767
filename: opts.filename,
6868
template: template,
6969
nodeVersion: nodeVersion,
70+
analytics: opts.analytics,
7071
}, cb);
7172
});
7273
}
@@ -128,6 +129,13 @@ function render(opts, cb) {
128129
gtocData.replace('class="nav-' + id, 'class="nav-' + id + ' active')
129130
);
130131

132+
if (opts.analytics) {
133+
template = template.replace(
134+
'<!-- __TRACKING__ -->',
135+
analyticsScript(opts.analytics)
136+
);
137+
}
138+
131139
// content has to be the last thing we do with
132140
// the lexed tokens, because it's destructive.
133141
const content = marked.parser(lexed);
@@ -137,6 +145,23 @@ function render(opts, cb) {
137145
});
138146
}
139147

148+
function analyticsScript(analytics) {
149+
return `
150+
<script src="assets/dnt_helper.js"></script>
151+
<script>
152+
if (!_dntEnabled()) {
153+
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;
154+
i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},
155+
i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];
156+
a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,
157+
'script','//www.google-analytics.com/analytics.js','ga');
158+
ga('create', '${analytics}', 'auto');
159+
ga('send', 'pageview');
160+
}
161+
</script>
162+
`;
163+
}
164+
140165
// handle general body-text replacements
141166
// for example, link man page references to the actual page
142167
function parseText(lexed) {

0 commit comments

Comments
 (0)
Please sign in to comment.