tags:

views:

111

answers:

6

My javascript code is added to random websites. I would like to be able to report to my server when a (specific) link/button on the a website is clicked. However I want to do it without any possible interruption to the website execution under any circumstances (such as error in my code, or my server id down etc.). In other words I want the site to do its default action regardless of my code.

The simple way to do it is adding event listener to the click event, calling the server synchronously to make sure the call is registered and then to execute the click. But I don't want my site and code to be able to cause the click not to complete.

Any other ideas on how to do that?

+1  A: 

As long as you don't return false; inside your callback and your AJAX is asynchronous I don't think you'll have any problems with your links not working.

$("a.track").mousedown(function(){ $.post("/tools/track.php") })

I would also suggest you encapsulating this whole logyc inside a try{} catch() block so that any errors encauntered will not prevent the normal click behaviour to continue.

duckyflip
your code (the identifier) requires JQuery, if his link is displayed on random website's it will not work when they don't have the jquery framework and adding it yourself will probably not be appreciated.
Peter
@Peter you are right, but I think it's safe to assume that most Javascript programmers are aware of the $ function and it's generic function. Of course you can always use getElementByTagName/Id, I think for the purposes of this example the code I provided is pretty self explanatory
duckyflip
@duckyflip, I don't think you should make that assumption. I speak Prototype but not JQuery - I am aware that JQuery uses $ but I don't know what it means. In this simple case it looks rather similar to the Prototype $, so the intent is clear; but in general I think your assumption is unwise.
Colin Fine
Thanks for answering. Unfortunately I can't use jQuery in this case.
Nir
A: 

The click should be processed normally.

1) If your javascript code has an error, the page might show an error icon in the status bar but it will continue the processing, it won't hang.

2) If your ajax request is asynchronous, the page will make that request and process the click simultaneously. If your server was down and the ajax request happening in the background timed out, it won't cause the click event to not get processed.

Click Upvote
+1  A: 

Perhaps something like this? I haven't tested it so it may contain some typo's but the idea is the same...

<script type="text/javascript">
function mylinkwasclicked(id){
    try{
        //this function is called asynchronously
        setTimeOut('handlingfunctionname('+id+');',10);
    }catch(e){
        //on whatever error occured nothing was interrupted
    }
    //always return true to allow the execution of the link
    return true;
}
</script>

then your link could look like this:

<a id="linkidentifier" href="somelink.html" onclick="mylinkwasclicked(5)" >click me!</a>

or you could add the onclick dynamically:

<script type="text/javascript">
    var link = document.getElementById('linkidentifier');
    link.onclick=function(){mylinkwasclicked(5);};
</script>
Peter
A: 

If you do the request to your server synchronously, you'll block the execution of the original event handler until the response is received, if you do it asynchronously, the original behaviour of the link or button may be doing a form post or changing the url of the document, which will interrupt your asynchronous request.

Ashraf Sabry
Yes, this is exactly the problem
Nir
+1  A: 

Attach this function:

(new Image()).src = 'http://example.com/track?url=' + escape(this.href)
    + '&' + Math.random();
  1. It is asynchronous (the 'pseudo image' is loaded in the background)
  2. It can be cross domain (unlike ajax)
  3. It uses the most basic Javascript functionalities

It can, however, miss some clicks, due to site unloading before the image request is done.

Maciej Łebkowski
Looks excellent but what can I do to avoid the call to the server being missed because the actual click on the link switches page.
Nir
You cannot — since the page cannot change it’s behavior. I guess you’ll have to use some statistics to measure how many clicks are missed. For example, if you track 97 clicks, and 100 landing pages (on some random group of people/websites) it means that you’re statistically 97% accurate :) and you have to adjust the measured number accordingly.
Maciej Łebkowski
A: 

Delay the page exit just long enough to ping your server url

function link_clicked(el)
{
  try {
    var img = new Image();
    img.src = 'http://you?url=' + escape(el.href) + '&rand=' + math.random();
    window.onbeforeunload = wait;
  }catch(e){}
  return true;
}

function wait()
{
  for (var a=0; a<100000000; a++){}
  // do not return anything or a message window will appear
}

so what we've done is add a small delay to the page exit to give the outbound ping enough time to register. You could also just call wait() in the click handler but that would add an unnecessary delay to links that don't exit the page. Set the delay to whatever gives good results without slowing down the user noticeably. Anything more than a second would be rude but a second is a long time for a request roundtrip that returns no data. Just make sure your server doesn't need any longer to process the request or simply dump to a log and process that later.

SpliFF
oh yeah, don't forget that different computers will take different amounts of time to run the loop. it's probably better to use setTimeout to unlock the loop via a global var.
SpliFF
dear anonymous arsehole, how was this "not helpful"? It answers the question exactly and improves on previous solutions.
SpliFF