Skip to content

Commit

Permalink
Define analytics in the global context to guard against `id="analyt…
Browse files Browse the repository at this point in the history
…ics"`.

This defines `analytics` in the global context to guard against HTML elements
on the page potentially named "analytics".  This is necessary because we now
have some docs pages with elements using `id="analytics"`.  Unfortunately,
due to a historical artifact in web-browser history it was once made possible
to access HTML elements, from JavaScript, by their ID on the `window` object:

   window["some-div-id"]

Unfortunately, Segment.io uses a JavaScript variable named `analytics`, and
it's not possible to `push` stats into an HTML DIV which happens to also be
named `analytics` and have those stats work. :)

Of course, it's best to use the facilities that were actually designed for
that, like `document.getElementById`, but historical reasons have caused
this `window` access technique to still be the behavior for modern browsers.

Ref: https://github.com/apollographql/engine-docs/pull/135
Ref: https://github.com/apollographql/engine-docs/commit/acd4a8e5
Ref: https://github.com/apollographql/engine-docs/blame/ec045186/source/index.md#L21
https://w3c.github.io/html/browsers.html#named-access-on-the-window-object.
  • Loading branch information
abernix committed Apr 13, 2018
1 parent d076d8d commit 544f1f4
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 1 deletion.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## vNEXT

* Elements with HTML IDs of `analytics` will no longer break Segment.io.
[PR #](https://github.com/meteor/meteor-theme-hexo/pull/)

## v1.0.5

* The search box is now pinned to the menu and won't scroll off the page when
Expand Down
15 changes: 14 additions & 1 deletion layout/layout.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,20 @@
<% } %>
<% if (config.apis && config.apis.segment) { %>
// Segment Tracking
<%#
We define `analytics` in the global context to guard against HTML elements on the page
potentially named "analytics". This is necessary because we have some docs pages with
elements using `id="analytics"` combined with a moment in browser history when IE thought
it would be fun (?) to allow accessing HTML elements by their ID on the `window` object:
https://w3c.github.io/html/browsers.html#named-access-on-the-window-object.
Luckily, a variable in the global scope takes precedence over that kind of access, and
sensible access to the ID is done through the HTML `Document` interface (that is to say,
via `document.getElementById()` and similar interfaces). This intentionally uses `var`,
rather than `let` to prevent throwing when Segment.io tries to re-declare it.
%>
var analytics;
<%# Segment.io's analytics code. %>
!function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","page","once","off","on"];analytics.factory=function(t){return function(){var e=Array.prototype.slice.call(arguments);e.unshift(t);analytics.push(e);return analytics}};for(var t=0;t<analytics.methods.length;t++){var e=analytics.methods[t];analytics[e]=analytics.factory(e)}analytics.load=function(t){var e=document.createElement("script");e.type="text/javascript";e.async=!0;e.src=("https:"===document.location.protocol?"https://":"http://")+"cdn.segment.com/analytics.js/v1/"+t+"/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(e,n)};analytics.SNIPPET_VERSION="3.1.0";
analytics.load("<%- config.apis.segment %>");
analytics.page()
Expand Down

0 comments on commit 544f1f4

Please sign in to comment.