I have a website, where I allow other developers to host content.
My aim is to log clicks on every hyperlink (even the content that is hosted by other developers) ,which exists on the page.
My initial approach was as follows:
$('a').click(function(event)
{
//do my logging
return true;
}
);
Now with the above approach , I am facing the following issues:
Developers may have images inside the anchor link, so the events target is an image rather than href
Many developers have their own way of handling an href click , using an onclick event rather than a simply href='' attr
Some developers add their custom attr , to the tag, and have custom functions to handle the clicks
so basically , the issue is , there is a huge variety of anchor tags available, and logging clicks is not as simple.
Many cases allowed me to log the data I wanted, but a few cases , broke the code badly.
My aim to post on this forum was:
to discuss what is the right approach to do hyperlink clicks logging in a dynamic environment
is there a plugin out there , which allows a functionality like this.
I know facebook and google have this , but they have a totol control, on what is being hosted in their environments.
Any help is greatly appreciated.
Adding a click handler to every link is not a good idea. You should make use of event delegation (which will only attach one event handler at the root of the document):
$(document).delegate('a', 'click', function(event) {
// logging
});
Update (17.12.2011):
Since jQuery 1.7, one would use .on() [docs]:
$(document).on('click', 'a', function(event) {
// logging
});
Regarding your problems:
Developers may have images inside the anchor link, so the events target is an image rather than href
Events bubble up as long as propagation is not canceled. It depends on what you want to log. With delegate the event.target property will point to the image, but this (inside the handler) will point to the a element.
So you should have no problems here (example: http://jsfiddle.net/cR4DE/).
But that also means to you will miss clicks if the developers cancel the propagation.
(Side note: You could solve this letting the event handler fire in the capturing phase, but IE does not support this (hence jQuery does not either).)
Many developers have their own way of handling an href click , using an onclick event rather than a simply href='' attr
This will not touch existing event handlers.
Some developers add their custom attr , to the tag, and have custom functions to handle the clicks
Not sure what you mean here.
It also depends on how the other content is included. E.g. the above code won't track clicks in iframes.
In your logging code you should check for the bad cases and deal accordingly.
For example in your first case i you get the image and walk the dom up until i would find an a tag and log the href from there.
There will be some cases in which you will not be able to do the logging but if they are small compared with the cases you can do that you will be fine :).
Related
[edit: adding more details about the scenario]
I am creating a tool which an app can include using a script tag; this tool adds an overlay to their app; that overlay includes a canvas and controls that I render onto the canvas. I would like the tool to be able to capture all input events and either handle them (if occurring over one of the rendered controls) and stop propagation to the app, or pass them on to the app (if not occurring over one of the rendered controls).
I am able to preempt all of the host app's input events except when the app registers an event on window using capturing, as follows:
window.addEventListener("mousedown", (e) => console.log("hi"), true);
Is there a way for my tool to inject a function that gets called before that?
No. If an event listener has been attached to the window in the capturing phase, there is no way to get any other listeners in ahead of it. This is because the window will be the first node to be notified of any events and the listeners are triggered in the order they were added. (I'm guessing this was done deliberately y the designer of the tool you're using. Not very end-user-friendly, IMO.)
The only way around it would be if you had a reference to the bound function, in which case you could use removeEventListener, add your own listener, then re-bind the original one. This seems unlikely, however, in your code.
You need one of your script tags to appear first in the page, ideally in the <head>. Then you get to attach your listener first.
For a few years now I use user-JavaScript to put additional input buttons and clickable span-elements on pages. Usually I manage to make this work, e.g.
span = document.createElement("span");
span.onclick = __oujs.onClickAddPage;
span.appendChild(document.createTextNode("Add page"));
containingDiv.appendChild(span);
Usually __oujs.onClickAddPage() is called when I click on that span-element.
However, yesterday a site made some changes (apparently I have no clue what they were) that causes clicking on my elements to not cause any events. In the example above __oujs.onClickAddPage() is not called any more. The same is true for input-elements of type "button".
As I'm using Opera, DragonFly shows that my span still is the top-most element in that particular area and, therefore, it should handle the click-event. However, I understand that they include jQuery, which might be part of the misery.
Is there a special technique (maybe with a name that Google knows of) they use to able to do such thing? How do I get the control back and have my code called again? Can I remove some object?
I'm sorry for asking in a rather broad style, but I have no clue what I can look for to fix this myself. Please ask if you need to know something.
I would suggest you this steps:
Create the next function:
function stubFn(event){
console.log('event caught', event); // this will log the click event
__oujs.onClickAddPage.call(event.currentTarget, event); // emulate the onclick behavior
}
Use span.addEventListener('click', stubFn) to add the listener to the element in your code.
If it does not work, then you have to reverse-engineer the script and markup.
I'd suggest to check if there is any element with absolute or fixed position overlapping your span. It can prevent the event propagation.
In general, there are no ways to forbid the elements from userscripts to handle events using inlined handlers.
To get this off my open questions I answer this myself rather than waiting for it to be closed:
I'm sorry, it was my fault. I had a stupid mistake in another user-JavaScript file that affected all sites...
I reinstalled my browser and was thinking about reinstalling my OS, but luckily this isn't necessary.
I am making a chrome extension to add javascript encryption to Gmail for my buddies and I personal use. I have most of it working except for when I try to clone a button already in the Gmail interface by doing $('#elmId').clone(true), it doesn't clone the event listeners. Also, $('#elmId').data('events') comes up with nothing. I know that the button has multiple event listeners because when I inspect element the developer tools shows it has click, mouseover, etc. under the "Event Listeners" tab (see http://i.stack.imgur.com/9KnIW.png & http://i.imgur.com/1sszQ.png). Is this even possible? I'v done quite a bit of searching and have come up with nothing. Any ideas on how to do this or if it is even possible?
Even if cloning the event listener is technically possible it doesn't mean it's meaningful. The listener may be a closure that knows about the element, using the same closure on a different element is not going to work... for example
x.onclick = function(){document.body.removeChild(x);}
in this case the onclick handler removes the element x, but if you copy the element and the handler clicking the copy would still close the original.
I am having anchor tag in my page. I like to trigger click event onload . Which means I wanna open this page "http://XXXXX.com" with new tab. Because I don't wanna popup blockers. Is there anyway to do this?
anchor attrs are given bellow
id="add_redirect"
href="http://XXXXX.com"
target="_blank"
Yeah, you can use a click event called onLoad(). Just use the setTimeout() method in jquery. It will call a click function without clicking it. Here is an example:
$("document").ready(function() {
setTimeout(function() {
$("#add_redirect").trigger('click');
},10);
});
This will work for you when the page start to load and the time delay is 10ms which is negligible.
Syntax has been corrected.
Try adding the following code in the page load
document.getElementById('add_redirect').click();
Using JQuery you can do that pretty easy. The earlier posted solution also work of course.
$(document).ready(function(){
$("#add_redirect").trigger('click');
});
TRY DEMO
If your goal is to bypass pop-up blockers on page load, triggering the click event synthetically probably won't work. Browsers are smart enough to know when a click is user-generated vs. when you've called the click function on the DOM element (on those browsers were that even works). Examples: http://jsbin.com/avibi3/3, http://jsbin.com/avibi3/4
Using jQuery's trigger mechanism certainly won't do it, because it doesn't really trigger a click event at all; it just fires the handlers that jQuery hooked up (edit: and, apparently, ones defined via an onclick attribute — see Sukhi's answer — but not ones attached via addEventListener). If that's what you want to do, Sukhi's answer shows you how, although I always say: If you want code to be run from two different places, put it in a function, and call that function from two different places (rather than putting it in a click handler and then simulating a click just to run the code). There are valid use cases for trigger (mostly relating to integrating with third-party scripts), but for running your own code from two different places, it's a symptom of a design problem.
I'm currently developing an ajax application and I'm looking for a feature that lets me intercept all static and dynamic links using javascript. The links look like these:
link 1
link 2
etc.
I then want the browser to redirect to: current.page/#link1/ rather than current.page/link1/. I'm using jQuery, so the live() function is an option, however using that as a solution just seems rather sluggish to me(am I hysterical?). If there is a way to intercept ALL links on a page, maybe through detecting a change in the address, that would greatly help. I've tried a few plugins for jQuery (jQuery address & SWFaddress) but they only seem to have event handlers that respond to changes in anchor tags in the address. Any ideas?
thanks for your time
Don't worry to much about performance unless you have to. Often the elegant solution is also the right one.
I would use jQuerys live function, bind to the click event and rewrite the link as it is being clicked on.
Hope this helps, Egil.
What the live function does is it binds an event handler to the document, which catches all click events and then detects all clicks that match the selector, in your case the link elements. This is the most efficient way of catching all link clicks.