Use JavaScript to intercept all document link clicks - javascript

How do I intercept link clicks in document?
It must be cross-platform.
I am looking for something like this:
// content is a div with innerHTML
var content = document.getElementById("ControlPanelContent");
content.addEventListener("click", ContentClick, false);
function ContentClick(event) {
if(event.href == "http://oldurl")
{
event.href = "http://newurl";
}
}

What about the case where the links are being generated while the page is being used? This occurs frequently with today's more complex front end frameworks.
The proper solution would probably be to put the click event listener on the document. This is because events on elements propagate to their parents and because a link is actually acted upon by the top-most parent.
This will work for all links, whether they are loaded with the page, or generated dynamically on the front end at any point in time.
function interceptClickEvent(e) {
var href;
var target = e.target || e.srcElement;
if (target.tagName === 'A') {
href = target.getAttribute('href');
//put your logic here...
if (true) {
//tell the browser not to respond to the link click
e.preventDefault();
}
}
}
//listen for link click events at the document level
if (document.addEventListener) {
document.addEventListener('click', interceptClickEvent);
} else if (document.attachEvent) {
document.attachEvent('onclick', interceptClickEvent);
}

for (var ls = document.links, numLinks = ls.length, i=0; i<numLinks; i++){
ls[i].href= "...torture puppies here...";
}
alternatively if you just want to intercept, not change, add an onclick handler. This will get called before navigating to the url:
var handler = function(){
...torment kittens here...
}
for (var ls = document.links, numLinks = ls.length, i=0; i<numLinks; i++){
ls[i].onclick= handler;
}
Note that document.links also contains AREA elements with a href attribute - not just A elements.

I just found this out and it may help some people. In addition to interception, if you want to disallow the link to load another page or reload the current page. Just set the href to '#' (as in internal page ref prefix). Now you can use the link to call a function while staying at the same page.

Related

Close all Angular JS Bootstrap popovers with click anywhere on screen?

I am using the Angular directives for bootstrap.
I have a popover as in their example:
<button popover="Hello, World!" popover-title="Title" class="btn btn-default ng-scope">Dynamic Popover</button>
It closes when you click on the button again. I'd like to close it -- and any other open popovers -- when the user clicks anywhere.
I don't see a built-in way to do this.
angular.element(document.body).bind('click', function (e) {
var popups = document.querySelectorAll('.popover');
if(popups) {
for(var i=0; i<popups.length; i++) {
var popup = popups[i];
var popupElement = angular.element(popup);
if(popupElement[0].previousSibling!=e.target){
popupElement.scope().$parent.isOpen=false;
popupElement.remove();
}
}
}
});
This feature request is being tracked (https://github.com/angular-ui/bootstrap/issues/618). Similar to aet's answer, you can do what is recommended in the feature request as a work-around:
$('body').on('click', function (e) {
$('*[popover]').each(function () {
//Only do this for all popovers other than the current one that cause this event
if (!($(this).is(e.target) || $(this).has(e.target).length > 0)
&& $(this).siblings('.popover').length !== 0
&& $(this).siblings('.popover').has(e.target).length === 0)
{
//Remove the popover element from the DOM
$(this).siblings('.popover').remove();
//Set the state of the popover in the scope to reflect this
angular.element(this).scope().tt_isOpen = false;
}
});
});
(source: vchatterji's comment in feature request mentioned above)
The feature request also has a non-jQuery solution as well as this plnkr: http://plnkr.co/edit/fhsy4V
angular.element(document.body).bind('click', function (e) {
var popups = document.querySelectorAll('.popover');
if (popups) {
for (var i = 0; i < popups.length; i++) {
var popup = popups[i];
var popupElement = angular.element(popup);
console.log(2);
if (popupElement[0].previousSibling != e.target) {
popupElement.scope().$parent.isOpen = false;
popupElement.scope().$parent.$apply();
}
}
}
});
What you say it's a default settings of the popover, but you can control it with the triggers function, by putting blur in the second argument of the trigger like this popover-trigger="{mouseenter:blur}"
One idea is you can change the trigger to use mouse enter and exit, which would ensure that only one popover shows at once. The following is an example of that:
<button popover="I appeared on mouse enter!"
popover-trigger="mouseenter" class="btn btn-default"
popover-placement="bottom" >Hello World</button>
You can see this working in this plunker. You can find the entire list of tooltip triggers on the angular bootstrap site (tooltips and popovers have the same trigger options). Best of luck!
Had the same requirement, and this is how we did it:
First, we modified bootstrap, in the link function of the tooltip:
if (prefix === "popover") {
element.addClass('popover-link');
}
Then, we run a click handler on the body like so:
$('body').on('click', function(e) {
var clickedOutside = true;
// popover-link comes from our modified ui-bootstrap-tpls
$('.popover-link').each(function() {
if ($(this).is(e.target) || $(this).has(e.target).length) {
clickedOutside = false;
return false;
}
});
if ($('.popover').has(e.target).length) {
clickedOutside = false;
}
if (clickedOutside) {
$('.popover').prev().click();
}
});
I am using below code for same
angular.element(document.body).popover({
selector: '[rel=popover]',
trigger: "click"
}).on("show.bs.popover", function(e){
angular.element("[rel=popover]").not(e.target).popover("destroy");
angular.element(".popover").remove();
});
Thank you Lauren Campregher, this is worked.
Your code is the only one that also runs the state change on the scope.
Only configured so that if you click on the popover, the latter closes.
I've mixed your code, and now also it works if you click inside the popover.
Whether the system, whether done through popover-template,
To make it recognizable pop up done with popover-template, I used classes popover- body and popover-title, corresponding to the header and the body of the popover made with the template, and making sure it is pointing directly at them place in the code:
angular.element(document.body).bind('click', function (e) {
var popups = document.querySelectorAll('.popover');
if(popups) {
for(var i=0; i<popups.length; i++) {
var popup = popups[i];
var popupElement = angular.element(popup);
var content;
var arrow;
if(popupElement.next()) {
//The following is the content child in the popovers first sibling
// For the classic popover with Angularjs Ui Bootstrap
content = popupElement[0].querySelector('.popover-content');
// For the templating popover (popover-template attrib) with Angularjs Ui Bootstrap
bodytempl = popupElement[0].querySelector('.popover-body');
headertempl= popupElement[0].querySelector('.popover-title');
//The following is the arrow child in the popovers first sibling
// For both cases.
arrow = popupElement[0].querySelector('.arrow');
}
if(popupElement[0].previousSibling!=e.target && e.target != content && e.target != arrow && e.target != bodytempl && e.target != headertempl){
popupElement.scope().$parent.isOpen=false;
popupElement.remove();
}
}
}
});
Have ever a good day, thank you Lauren, thank you AngularJS, Thank You So Much Stack Family!
Updated:
I updated all adding extra control.
The elements within the popover were excluded from the control (for example, a picture inserted into the body of the popover.). Then clicking on the same closed.
I used to solve the command of API Node.contains, integrated in a function that returns true or false.
Now with any element placed inside, run the control, and keeps the popover open if you click inside :
// function for checkparent with Node.contains
function check(parentNode, childNode) { if('contains' in parentNode) { return parentNode.contains(childNode); } else { return parentNode.compareDocumentPosition(childNode) % 16; }}
angular.element(document.body).bind('click', function (e) {
var popups = document.querySelectorAll('.popover');
if(popups) {
for(var i=0; i<popups.length; i++) {
var popup = popups[i];
var popupElement = angular.element(popup);
var content;
var arrow;
if(popupElement.next()) {
//The following is the content child in the popovers first sibling
// For the classic popover with Angularjs Ui Bootstrap
content = popupElement[0].querySelector('.popover-content');
// For the templating popover (popover-template attrib) with Angularjs Ui Bootstrap
bodytempl = popupElement[0].querySelector('.popover-body');
headertempl= popupElement[0].querySelector('.popover-title');
//The following is the arrow child in the popovers first sibling
// For both cases.
arrow = popupElement[0].querySelector('.arrow');
}
var checkel= check(content,e.target);
if(popupElement[0].previousSibling!=e.target && e.target != content && e.target != arrow && e.target != bodytempl && e.target != headertempl&& checkel == false){
popupElement.scope().$parent.isOpen=false;
popupElement.remove();
}
}
}
});

How to detect a user clicked on an internal or external link

I need to know if users clicked on an internal or external link to alert them.
I have many internal and external links on my site.
My internal links are like this:
about
draw graph
I need to alert only when external links are clicked.
(I've included two methods here: One method uses jQuery, and the other doesn't use jQuery. Skip down to the bold heading if you don't want to use jQuery)
One way you could do this is by adding a class to each external link, and then attaching an event handler to everything in that class which raises an alert when you click the link. That's tedious, though, as you have to add the class to every external link, and it won't for user generated content.
What you can do is use jQuery, along with the CSS selector a[href^="http"], to select all the external links, and then attach an event handler that raises your alert when they're clicked:
$('a[href^="http"]').click(function() {
alert();
});
a[href^="http"] means "an a tag which has a link, and that link has to start with 'http'." So here we select all the elements which start with http - that is, every external link - and then set it so that when you click on them, an alert pops up.
Non-jQuery method
If you want to do this without jQuery, you'll want to use document.querySelectorAll('a[href^="http"]') and bind the click event of each element in the array that that function returns. That looks something like this:
var externalLinks = document.querySelectorAll('a[href^="http"]');
for (var i = externalLinks.length-1; i >= 0; i--) {
externalLinks[i].addEventListener("click", function() { alert(); }, false);
}
I had to do this from scratch on my own site so I'll just copy + paste it here for you. It came from inside one of my objects so if I left some this keywords you can remove them.
function leaving() {
var links = document.anchors || document.links || document.getElementsByTagName('a');
for (var i = 0; i < links.length; i++) {
if ((links[i].getAttribute('href').indexOf('http') === 0 && links[i].getAttribute('href').indexOf('fleeceitout') < 0) && (links[i].getAttribute('href').indexOf('/') !== 0 && links[i].getAttribute('href').indexOf('#') !== 0) && links[i].className.indexOf('colorbox') < 0) {
addEvent(links[i], 'click', this.action);
}
}
}
function action(evt) {
var e = evt || window.event,
link = (e.currentTarget) ? e.currentTarget : e.srcElement;
if (e.preventDefault) {
e.preventDefault();
} else {
window.location.href = link.href;
return;
}
var leave = confirm("You are now leaving the _______ website. If you want to stay, click cancel.");
if (leave) {
window.location.href = link.href;
return;
} else {
return leave;
}
}
var addEvent = function (element, myEvent, fnc) {
return ((element.attachEvent) ? element.attachEvent('on' + myEvent, fnc) : element.addEventListener(myEvent, fnc, false));
};
Replace instances of 'fleeceitout' with your sites domain name (microsoft.com, etc) and you're set.
The easiest ways are with jQuery, using a special class for external links, or by checking for "http://" in the URL.
Like this, if using a special class:
$("a.external").on("click", function() {
//de Do something special here, before going to the link.
//de URL is: $(this).attr("href")
});
And then in HTML:
<a href="http://external.link" class='external'>external link</a>
Or, you can check for http:// in the URL! Then you don't need a special class.
$('a[href=^"http://"]').on("click", function() {
//de Do something special here, before going to the link.
//de URL is: $(this).attr("href")
});
Cite: My original method of testing for "http://" was a bit slower, actually doing an indexOf test on .attr("href") so I used #Matthew's selector choice instead. Forgot about the caret route! Props to #Matthew on that, and for the non-jQuery alternative.
$(document).ready(function() {
$('a').click(function() {
var returnType= true;
var link = $(this).attr('href');
if ( link.indexOf('http') >= 0 ) {
returnType=confirm('You are browsing to an external link.');
}
return returnType;
});
});`

Capturing all the <a> click event

I am thinking of to add a javascript function to capture all the <a> click events inside a html page.
So I am adding a global function that governs all the <a> click events, but not adding onclick to each (neither using .onclick= nor attachEvent(onclick...) nor inline onclick=). I will leave each <a> as simple as <a href="someurl"> within the html without touching them.
I tried window.onclick = function (e) {...}
but that just captures all the clicks
How do I specify only the clicks on <a> and to extract the links inside <a> that is being clicked?
Restriction: I don't want to use any exra libraries like jQuery, just vanilla javascript.
Use event delegation:
document.addEventListener(`click`, e => {
const origin = e.target.closest(`a`);
if (origin) {
console.clear();
console.log(`You clicked ${origin.href}`);
}
});
<div>
some link
<div><div><i>some other (nested) link</i></div></div>
</div>
[edit 2020/08/20] Modernized
You can handle all click using window.onclick and then filter using event.target
Example as you asked:
<html>
<head>
<script type="text/javascript">
window.onclick = function(e) { alert(e.target);};
</script>
</head>
<body>
google
yahoo
facebook
</body>
</html>
​window.onclick = function (e) {
if (e.target.localName == 'a') {
console.log('a tag clicked!');
}
}​
The working demo.
your idea to delegate the event to the window and then check if the "event.target" is a link, is one way to go (better would be document.body). The trouble here is that it won't work if you click on a child node of your element. Think:
<b>I am bold</b>
the target would be the <b> element, not the link. This means checking for e.target won't work. So, you would have to crawl up all the dom tree to check if the clicked element is a descendant of a <a> element.
Another method that requires less computation on every click, but costs more to initialize would be to get all <a> tags and attach your event in a loop:
var links = Array.prototype.slice.call(
document.getElementsByTagName('a')
);
var count = links.length;
for(var i = 0; i < count; i++) {
links[i].addEventListener('click', function(e) {
//your code here
});
}
(PS: why do I convert the HTMLCollection to array? here's the answer.)
You need to take into account that a link can be nested with other elements and want to traverse the tree back to the 'a' element. This works for me:
window.onclick = function(e) {
var node = e.target;
while (node != undefined && node.localName != 'a') {
node = node.parentNode;
}
if (node != undefined) {
console.log(node.href);
/* Your link handler here */
return false; // stop handling the click
} else {
return true; // handle other clicks
}
}
See e.g. https://jsfiddle.net/hnmdijkema/nn5akf3b/6/
You can also try using this:
var forEach = Array.prototype.forEach;
var links = document.getElementsByTagName('a');
forEach.call(links, function (link) {
link.onclick = function () {
console.log('Clicked');
}
});
It works, I just tested!
Working Demo: http://jsfiddle.net/CR7Sz/
Somewhere in comments you mentioned you want to get the 'href' value you can do that with this:
var forEach = Array.prototype.forEach;
var links = document.getElementsByTagName('a');
forEach.call(links, function (link) {
link.onclick = function () {
console.log(link.href); //use link.href for the value
}
});
Demo: http://jsfiddle.net/CR7Sz/1/
Try jQuery and
$('a').click(function(event) { *your code here* });
In this function you can extract href value in this way:
$(this).attr('href')
Some accepted answers dont work with nested elements like:
<font><u>link</u></font>
There is a basic solution for most cases:
```
var links = document.getElementsByTagName('a');
for(var i in links)
{
links[i].onclick = function(e){
e.preventDefault();
var href = this.href;
// ... do what you need here.
}
}
If anybody is looking for the typed version (TypeScript, using Kooilnc's answer), here it is:
document.addEventListener("click", (e: Event) => {
if(!e.target) { return; }
if(!(e.target instanceof Element)) { return; }
const origin = e.target.closest("a");
if(!origin || !origin.href) { return; }
console.log(`You clicked ${origin.href}`);
});
I guess this simple code will work with jquery.
$("a").click(function(){
alert($(this).attr('href'));
});
Without JQuery:
window.onclick = function(e) {
if(e.target.localName=='a')
alert(e.target);
};
The above will produce the same result.
Very simple :
document.getElementById("YOUR_ID").onclick = function (e) {...}
The selector is what you want to select so lets say you have button called
Button1
The code to capure this is:
document.getElementById("button1").onclick = function (e) { alert('button1 clicked'); }
Hope that helps.

Detecting when user touches a link

I'm trying to detect when the user has touched a link within a web page versus when they have touched any other part of the page, but its not working - what happens is in the following code the alert "touched a non link" pops up wherever I touch, regardless of if its a link.
What is there a problem with this code?
function addListeners()
{
alert('adding listeners');
// Attach the listener for touches on non-links to the document node
document.addEventListener("touchstart", touchesOnNonLinksListerner, false);
// Attach the listener for touches on links to the anchor nodes
var links = document.getElementsByTagName("a");
for (var index = 0; index < links.length; ++index)
{
links[index].addEventListener("touchstart", touchesOnNonLinksListerner, false);
}
};
function touchesOnNonLinksListerner(event)
// Catches touches anywhere in the document
{
alert("touched a non link");
}
function touchesOnLinksListener(event)
// Listens for touches which occur on links, then prevents those touch events from bubbling up to trigger the touchesOnNonLinksListerner
{
alert("touched a link");
if (typeof event == "undefined")
{
event = window.event;
}
event.stopPropegation();
}
You have attached touchesOnNonLinksListerner to your links as well. Attach touchesOnLinksListener instead!

Check if elemntFromPoint() bumps into a hyperlink

I am using elemntFromPoint in order to return onclick some element. I would like to check if the returned element ('span' div' whatever...) is part of a link or if it is a button etc. How should I start? Thanks.
To check if the element "is part of a link" you'll want to traverse up the DOM tree until you hit an anchor - if you don't hit an anchor then the element isn't in a link. E.g.
var el = document.elementFromPoint(x,y),
cur = el,
isInAnchor = false;
do {
if (cur.nodeName.toLowerCase() === 'a') {
isInAnchor = true;
break;
}
} while (cur = cur.parentNode);
alert(isInAnchor); // either true or false

Categories

Resources