16

I'm trying to write a Cross-Browser script that detects when a link is clicked on a page (text link, image, or othwerwise) so that I can show a message or ad (like an interstitial) and then direct the visitor to the originally clicked destination url.

The script has to work from 3rd party sites (where the owner installs the script tags on his or her site).

How can I accomplish this using javascript?

Do I use an event listener? Do I iterate through all link objects? Or something else?

My javascript skills are newbie/intermediate so detailed examples/explanations are greatly appreciated.

I've started off using the event listener here, but so far I'm detecting ALL clicks on the page: addEventListener Code Snippet Translation and Usage for cross-browser detectioin

I'll consider a JQuery alternative, but I just don't know how it'll work on 3rd party site if that site doesn't have the JQuery library.

Thanks all.

Community
  • 1
  • 1
C King
  • 281
  • 1
  • 5
  • 14
  • 1
    One thing you're probably going to have to deal with eventually is that some sites will have their own handlers for link clicks, and it's going to be hard/impossible to ensure that your handler is called first. – Pointy Dec 09 '11 at 22:18
  • @Pointy - This is a good point... didn't even consider that. I'll just have to point out the typical caveats and disclaimers to anyone using my code. – C King Dec 09 '11 at 23:10

4 Answers4

17

To call a function whenever a link—dynamically added or not—has been clicked, use on()

$(document).on("click", "a", function() {
    //this == the link that was clicked
    var href = $(this).attr("href");
    alert("You're trying to go to " + href);
});

If you're using an older version of jQuery, then you would use delegate() (note that the order of selector and event type is switched)

$(document).delegate("a", "click", function() {
    //this == the link that was clicked
    var href = $(this).attr("href");
    alert("You're trying to go to " + href);
});
Adam Rackis
  • 82,527
  • 56
  • 270
  • 393
  • Thanks for this, I didn't realize this was a function. +1 – danludwig Dec 09 '11 at 21:19
  • I take it back -- now I have to go change all of my live() calls since it is now deprecated. Darn you! – danludwig Dec 09 '11 at 21:27
  • @olivehour - ha! I used to use live with gusto not knowing it was deprecated. To be honest, the only downside with live is that it goes through your dom at the time it was called and wraps all links (or whatever) it finds and hooks up the event. It's that initial processing time that's obviated with delegate and on. Unless you have a crazy complicated page, it probably won't make a difference. Just leave it :) – Adam Rackis Dec 09 '11 at 21:36
  • Another reason why spending a day on StackOverflow answering questions makes you a better programmer! – danludwig Dec 09 '11 at 21:45
  • @olivehour - totally. I have learned reams and reams answering questions on SO. – Adam Rackis Dec 09 '11 at 21:54
13

I thought I'd try a non-jQuery (and non-other-library solution too, just for...well, filling a few minutes):

function clickOrigin(e){
    var target = e.target;
    var tag = [];
    tag.tagType = target.tagName.toLowerCase();
    tag.tagClass = target.className.split(' ');
    tag.id = target.id;
    tag.parent = target.parentNode;

    return tag;
}

var tagsToIdentify = ['img','a'];

document.body.onclick = function(e){
    elem = clickOrigin(e);

    for (i=0;i<tagsToIdentify.length;i++){
        if (elem.tagType == tagsToIdentify[i]){
            console.log('You\'ve clicked a monitored tag (' + elem.tagType + ', in this case).');
            return false; // or do something else.
        }
    }
};

JS Fiddle demo.

Amended the above, to detect img elements nested within an a element (which I think is what you're wanting having re-read your question):

function clickOrigin(e){
    var target = e.target;
    var tag = [];
    tag.tagType = target.tagName.toLowerCase();
    tag.tagClass = target.className.split(' ');
    tag.id = target.id;
    tag.parent = target.parentNode.tagName.toLowerCase();

    return tag;
}

var tagsToIdentify = ['img','a'];

document.body.onclick = function(e){
    elem = clickOrigin(e);

    for (i=0;i<tagsToIdentify.length;i++){
        if (elem.tagType == tagsToIdentify[i] && elem.parent == 'a'){
            console.log('You\'ve clicked a monitored tag (' + elem.tagType + ', in this case and one inside an "a" element, no less!).');
            return false; // or do something else.
        }
        else if (elem.tagType == tagsToIdentify[i]){
            console.log('You\'ve clicked a monitored tag (' + elem.tagType + ', in this case).');
            return false; // or do something else.
        }
    }
};

JS Fiddle demo.

David Thomas
  • 249,100
  • 51
  • 377
  • 410
  • +1 - really cool, but why is `var tag = [];` instead of `var tag = {};`? Isn't it bad to put dynamic properties onto an array? – Adam Rackis Dec 09 '11 at 22:10
  • Also for IE you probably want to check for `e.srcElement` if there's no "target" property on the event. – Pointy Dec 09 '11 at 22:17
  • @AdamRackis, it possibly is, but I was unaware of that until your comment (I sort of learned JavaScript by accident, via jQuery...so I can use it (happily!), but not necessarily 'well'). – David Thomas Dec 09 '11 at 22:27
  • @Pointy, so that'd become: `var target = e.target || e.srcElement;`? I don't have IE to play with (I'm merely a hobbyist, so... *shrugs*) to find out for myself, sadly =/ – David Thomas Dec 09 '11 at 22:28
1

This is roughly how to do it without use of jQuery:

<html>

    <head>
            <script type="text/javascript">
            window.onload = function() {
              var observed = document.getElementsByTagName('a');

              for (var i = 0; i < observed.length; i++) {
                observed[i].addEventListener('click', function (e) {
                   var e=window.event||e;

                   alert('Clicked ' + e.srcElement.innerText);

                   if (e.preventDefault) { e.preventDefault() } else { e.returnValue=false }
                }, false);
              }
            }
            </script>
    </head>


    <body>

            <a href="">foo</a>
            <a href="">bar</a>

    </body>
</html>
Adam Rackis
  • 82,527
  • 56
  • 270
  • 393
0

i use this that way it only affects the a tags with links in them,

(function($){
$("a[href!='']").each(function(){
    $(this).click(function(){
    var href = $(this).attr("href")
    })
});
})(jQuery);

But on this note you say your wanting people to use this on 3rd party web sites so they might not have jQuery so you might need this check in the top of your file but then you will need to include your file after use the same code but check for your object or a function name

if(typeof(jQuery) == undefined){
    var head = docuent.getElementsByTagName('head')[0];
    var script = document.createElement("script");
    script.setAttribute("type", "text/javascript");
    script.setAttribute("src", "http://yourserver.url/jquery.js");
    head.appendChild(script);
}
Barkermn01
  • 6,781
  • 33
  • 83
  • Martin, that 2nd part is a nice bit of code. Just for future reference - after appending script tag, will page need reloading to run rest of script? – C King Dec 09 '11 at 23:48
  • Yes and no the page does not need to reload once script tag containing that code has finished it will load in (download) your jQuery file – Barkermn01 Dec 12 '11 at 10:06
  • The reason for the rejection on the edit is when this post was answered a lot of browsers did not support the `document.head` see https://developer.mozilla.org/en-US/docs/Web/API/Document/head#Browser_compatibility for compatibility support – Barkermn01 Dec 15 '18 at 21:37