Adding Google Analytics to DominoWiki - Nightmare!
The other week I added Google Analytics to all the web-facing applications I'd produced for a customer. They then asked if I'd mind adding it to a copy of DominoWiki they used. "Not at all" I said, knowing it to be a two minute copy-paste task.
The trouble is it turned in to a two hour job!
Google Analytics adds itself to a page using this line of code:
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
This adds a Script tag to the document and loads the required code from Google's site. That's the idea. On the DominoWiki page it didn't add a tag though. It just wrote the escaped string to document itself as visible text.
The first thing I did was add some more JavaScript lines to test the result of escape('<'), which it bizarrely returned as '<'. Since when did escaping do that!?
After about an hour of messing about with charset settings and whatnot I started to reverse engineer the page to the point where I found that removing the reference to the wiki.js file solved the problem. Looking about in that file I found the following function:
/* unescape Decode an XML string */ function unescape(s) { var n = s; n = n.replace(/</g, "<"); n = n.replace(/>/g, ">"); n = n.replace(/"/g, "\""); n = n.replace(/&/g, "&"); return n; }
Whoever coded this part of the Wiki had re-written the built-in escape/unescape JavaScript functions. I'm sure I don't need to tell you how naughty that is. Not only bad practice but just plain annoying for the likes of me who come in afterward to do anything and spend half their morning struggling to work it all out.
The fix is simple enough. Just add the following two lines to the unescape() function in wiki.js:
//Following two lines required for Google Analytics to work n = n.replace(/%3C/g, "<"); n = n.replace(/%3E;/g, ">");
Here's a massive list of "reserved" words you should avoid using in your own code as variables or function names.
If you really want a function called unescape then it's better defined within your own global object. For example the wiki.js file could contain this code:var Wiki = {}; Wiki.unescape = function(s) { var n = s; n = n.replace(/</g, "<"); n = n.replace(/>/g, ">"); n = n.replace(/"/g, "\""); n = n.replace(/&/g, "&"); return n; }
There's then little to no chance of the code conflicting. Not just with others developers code but also with the inbuilt code of the browser.
Right then, back to what I should have been doing...
I would be tempted to change the whole function to use a switch, and have the default case return javascript's unescape of the passed string.
(Using your scoping, however)
This is a case of lazy or ignorant programming! The first rule (or at least one rule) of good programming is do not create global variables/code when local is all that's required.
I try to keep all my code in my own objects. This way I create a single global object and everything else is inside of that.
You can blame the DominoWiki programmer but the Google programmer could have done the same thing, knowing that his/her code will be loaded into a completely unknown environment.
I don't think it's fair to point fingers at Google for expecting unescape to do what it does. Surely you wouldn't write all your code without using any of the inbuilt JavaScript functions just in case somebody has over-rode them?
Jake
Hi All,
Yes, I agree that built-in javascript function/keywords should be kept alone.
Regards !
Domino Guy
I had the same problem with Google Analytics ... except different.
I was using a setting doc (a method taken from one of Jake's templates) to store the Analytics code. I then inherited the code into the HTML head content using @DBLookup, a handy method if you're planning on using the same Analytics code on several forms.
Then, in the HTML head content, I used @Text with the variable that I had set with the @DBLookup and got the same result... the script actually wrote to the page in plain text. After fiddling with some things (for 2 hours) I simply changed the @Text to @Implode and it worked.
The nice thing about this method, no JavaScript.
Another quick note: Google says that you shouldn't use both code versions on the same page, I.E. urchin.js with the new version that Google has put out. (I can't remember the new file name.)
For me this was a bit of a pain because I was using two seperate programs for Analytics. Google's doesn't require the urchin.js, while my other service does. I don't remember how I came up with a fix for this, but when I do, I'll make sure and post it ... if anyone else has had the same problem.
I disagree. Rewriting the escape/unescape function is a good practice for preventing an XSS attax - and those preventing an user to submit some js code that would be executed in some other user's context when he just open the site.
And face it - that is exactly what yue have tryed to do - executing an additional javascript (that is loaded from an external server) when a user opens a page. Sounds pretty evil to me ;-)
Yeah Gregory, but Jake's not just some user submitting javascript to a site...He's writing the damn thing!
I really don't know much about Google Analytics, just that someone in our web marketing department asking me to paste the javascript onto a couple of my web forms. Is it sufficient for me to paste the content onto a form between <script>..</script> tags and make pass thru html?
Yes Bob. Make sure it's right at the end of the form.
Hi Jake, One more question - I pasted the script onto the form physically at the end, but when I view the source code of the web page there are some <Input> tags (fields) that appear between the </script> tag of the analytics and the </body> tag of the form, will this impact performance or should it be okay?
Thanks for your very quick response here, as well as for all the indirect help you have given me throughout the years!!!
Sounds like the form has "generate HTML for all fields turned on". Shouldn't be a problem though. There's only one way to find out though...
Duh, that was it. Thanks so much once again!!!