ClickTale Support Forums

All times are UTC - 6 hours



Post new topic Reply to topic  [ 7 posts ] 
Author Message
PostPosted: Wed Jun 06, 2007 5:50 pm 
Offline

Joined: Wed Jun 06, 2007 5:21 pm
Posts: 4
I'm not a big fan of inline JavaScript, so I set out to integrate ClickTale through one JavaScript include instead of the method given on the install pages. I force-recorded a couple pages and it seems to work fine. (On a side note, if you don't want to install the force-record HTML page, you can add the JS functions from the HTML page into your JS include and run javascrpit: URLs of the stuff in the button onclick... it makes it a little easier to use if you are using weird mod_rewrite stuff)

Advantages: If you already have a global JS file and aren't using a global template, this method is easy to implement. If you aren't using a template at all, this method is easy to implement.

Disadvantages: Since I'm new to CT, I'm not sure if it works all the time. If you don't have a BODY tag, this script may not work.

How it works:

Add the following HTML to your page (probably in the HEAD):

Code:
<script type="text/javascript" src="js/ct.js"></script>


Add the following JavaScript to js/ct.js:

Code:

// Waits on the ClickTale function to become available.
// If it isn't, the function is run until it is.
function ct_wait(){
   if(typeof ClickTale=='function') {
      ClickTale([!YOUR PROJECT ID!],[!YOUR RATIO!]);
   } else {
      setTimeout(ct_wait,1);
   }
}

// This creates the empty ClickTale DIV and appends it to the body.
// Then it creates the ClickTale SCRIPT and appends it.
//  Then it runs the ct_wait to wait for the ClickTale function to appear.
function init(){
   bod = document.getElementsByTagName("body")[0];
   ct_div = document.createElement("div");
   ct_div.id = "ClickTale";
   ct_div.style.display = "none;"
   bod.appendChild(ct_div);

   ct_script = document.createElement("script");
   ct_script.setAttribute('type', 'text/javascript');
   ct_script.setAttribute('src', "http://s.clicktale.net/WRa.js");
   bod.appendChild(ct_script);
   
   ct_wait();
}

// Sets the WRInitTime, as per CT's install scripts.
var WRInitTime=(new Date()).getTime();

// This can be done with DOM event handling
// so as not to trample onloads, but for simplicity,
// I'm using the short hand window.onload = .
window.onload = init;



The only thing this blatantly ignores is the WRInitTime variable being set before the BODY. I don't know how this affects ClickTale on a larger scale, but it didn't seem to damage any of my recordings.

If Arik has any comments, I'd like to hear them. If something like this could be included in http://s.clicktale.net/WRa.js, it might reduce the implementation time and be a little bit easier on total newbs.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 07, 2007 5:13 am 
Offline
Site Admin

Joined: Fri Jul 21, 2006 2:39 pm
Posts: 1206
Location: Israel
Ok, very interesting work. Here are my comments:

Setting WRInitTime in the head is ok. Basically it should be set as early as possible.

The main issue here is that ClickTale will be loaded only AFTER the entire page is loaded. First, ClickTale will miss the onload and ondomload events and second you will miss everything that the user has done prior to a complete load of the page.

Some pages can load for 10 of more seconds so I think this is significant.
BTW, there is a "Long load time" favourite search you can use to see how is this relevant to your site.

Any ideas?

Arik.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 07, 2007 11:56 am 
Offline

Joined: Wed Jun 06, 2007 5:21 pm
Posts: 4
I've never written anything with DOMContentLoaded; after scouring around, I think I came up with a decent cross-browser solution. It borrows stuff from all over the place, but it appears to work in more of the way inline code would work. That is, it fires before onload. I'm not sure what CT does on DOMContentLoaded, though.

If this were integrated into WRa.js, it's DOMContentLoaded events could be used still. What I'm trying to make up for is the inline JS. Not editing the WRa.js file will always be a bit short of an ideal solution. The question is whether I can get relatively close without major drawbacks.

Code:
function ct_monitorScriptLoad() {
   if(typeof ClickTale=='function') {
      ClickTale([!YOUR PROJECT ID!],[!YOUR RATIO!]);
      if(typeof WRondomload=="function") WRondomload();
   } else {
      setTimeout(ct_monitorScriptLoad,1);
   }
   if(typeof WRondomload=="function") {
      WRondomload();
   } else {
      setTimeout(ct_monitorScriptLoad,1);
   }
}
 
function ct_appendScripts() {
   var page_body = document.getElementsByTagName("body")[0];
   var ct_div = document.createElement("div");
   ct_div.id = "ClickTale";
   ct_div.style.display = "none;"
   page_body.appendChild(ct_div);

   var ct_script = document.createElement("script");
   ct_script.setAttribute('type', 'text/javascript');
   ct_script.setAttribute('src', "http://s.clicktale.net/WRa.js");
   page_body.appendChild(ct_script);
   
   ct_monitorScriptLoad();
}

function ct_monitorReadyState() {
   /loaded|complete/.test(document.readyState) ? ct_appendScripts() : setTimeout(ct_monitorReadyState, 1);
}

function ct_monitorBody() {
   var page_html = document.getElementsByTagName("html")[0].innerHTML;
   /<\/body>/i.test(page_html) ? ct_appendScripts() : setTimeout(ct_monitorBody, 1);
}
 
function ct_addEvents() {
   if(window.addEventListener) {
      // FireFox 2.0.0.4, Opera 9.21, and maybe future versions of Safari.
      window.addEventListener("DOMContentLoaded", ct_appendScripts, false);
      
      // Older Opera and current Safari
      if(/WebKit|Khtml/i.test(navigator.userAgent) || (window.opera && parseInt(window.opera.version()) < 9)) {
         ct_monitorReadyState();
      }
   } else {
      // IE doesn't do readyState like other browsers.  So, we have to monitor for the closing body tag.
      // If there is no body tag or no closing tag, no worries.  IE inserts it into the DOM anyway.
      ct_monitorBody();
   }
}
var WRInitTime=(new Date()).getTime();
ct_addEvents();


Edit: I still had ct_wait in the setTimeout instead of ct_monitorScriptLoad. I changed that line and added the DOM onload line as Arik suggested to ct_monitorScriptLoad:
Code:
   if(typeof WRondomload=="function") {
      WRondomload();
   } else {
      setTimeout(ct_monitorScriptLoad,1);
   }


Last edited by robertdot on Sun Jun 10, 2007 4:55 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 07, 2007 3:38 pm 
Offline
Site Admin

Joined: Fri Jul 21, 2006 2:39 pm
Posts: 1206
Location: Israel
Very nice!
robertdot - the guy who takes javascript and slaps it on the face with a rubber hose... :wink:

It should work pretty good. And if you add:
if(typeof WRondomload=="function") WRondomload();
after the call to ClickTale(...) it would make up for missing the ondomloaded event.

The only thing that worries me is your aggressive timeouts. The 1 stands for 1ms. Any reason why you used that in particular?

Arik.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 07, 2007 5:31 pm 
Offline

Joined: Wed Jun 06, 2007 5:21 pm
Posts: 4
The goal was to have the ct_appendScripts run as quickly after the DOM was loaded as possible (if possible before the onload event was fired, given a plain-old HMTL file with no images, due to the concerns raised before), as neither Safari or IE will load when the DOM is actually finished loading. 1ms may be too quick for what is needed. 10 or 100 could probably work. I don't have any evidence that 1ms would cause a major performance hit over 10ms or 100ms, so I went with the quickest.

I added the DOMOnload function call, as you suggested, to my implementation. I'm not currently getting as much traffic as I expected. So, I'll let this run awhile and post the final script if I think it is working properly.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 08, 2007 10:35 am 
Offline
Site Admin

Joined: Fri Jul 21, 2006 2:39 pm
Posts: 1206
Location: Israel
Robert,

Here is a technique I know for detecting DOMLoad with IE:

Code:
document.write('<script id="CTLoaderDefer" defer="defer" src=//:><\/script>');
document.getElementById("CTLoaderDefer").onreadystatechange = function()
   {
      if(this.readyState == "complete")
         ct_appendScripts();
   };


This will be better than searching in the innerHTML of the root.

Cheers,
Arik.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 08, 2007 11:44 am 
Offline

Joined: Wed Jun 06, 2007 5:21 pm
Posts: 4
I tried that originally. However, when I included a very large image on the page, the script wasn't run until after the image loaded in both IE6 and IE7, which was as good as using the onload event. Since that was not acceptable, I set about searching for the body close tag.


Edit: On second thought, I was using some version that didn't rely on the ID of the script element. I was worried that, given infinite possibilities, someone might have something else with the same ID I had reserved at some point, which would cause problems.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group