Preventing clicking of links using Javascript - javascript

$('a').click(function(e){return false;});
It successfully disables links almost everywhere but does not work on the links found in the tooltip-popups on the topic tags on this site (SO). I looked at the DOM and they are indeed <a> tags.
How come?
Is there a more robust way to force my user to stay on the current page? (This is for a bookmarklet where I graphically manipulate the DOM so I need to be able to click and drag everything, including links.)
I know that even if I can disable the regular click functionality on all anchors it won't do anything for any navigation triggered by other click callbacks on other tags.

try with .on - in e.g. SO sites those links are created later then your event attached
$(document).on('click', 'a', function(e) {
return false;
});

A technique I've employed before is to place an invisible absolutely-positioned element over the entire document. This is actually employed by Firebug Lite to allow the Element Inspector to intercept any clicks.
All you need to worry about then is attaching your event listener to your absolutely-positioned element and figuring out what element was under the mouse when you clicked. Luckily, all modern browsers implement a method to discern this: document.elementFromPoint. There are a few differences between implementations; here's the method I usually use (unfortunately feature detection's a bit tricky for this, so I'm doing browser detection):
var scrollIsRelative = !($.browser.opera || $.browser.safari && $.browser.version < "532");
$.fromPoint = function(x, y) {
if(!document.elementFromPoint) return null;
if(scrollIsRelative)
{
x -= $(document).scrollLeft();
y -= $(document).scrollTop();
}
return document.elementFromPoint(x, y);
};
Attach a click event listener to your absolutely-positioned div and on click, hide your div and call this method to get the element, then show your div again. Example:
$('#hugeDiv').on('click', function(ev) {
var x = ev.pageX;
var y = ev.pageY;
$(this).hide();
var el = $.fromPoint(x, y);
$(this).show();
//do stuff with el
});

It would appear the solution is
window.onbeforeunload = function() {
return "Are you sure you want to navigate away?";
}
A right proper use of an event system if I would say so myself.
The original scope of the question was not wide enough. This solves the problem that led to my question.

Related

Prevent child event from firing

I have a slider that I am currently making. I am making slow progress, but I am making progress nonetheless!
Currently I have this:
http://codepen.io/r3plica/pen/mEKyGG?editors=1011#0
There are 2 things you can do with this control, the first thing is you can drag left or right. The second thing you can do is click a "point" and it will scroll to the center.
The problem I have is that if I start dragging from a point, when I let go it will invoke the moveToCenter method.
I have tried to prevent this by adding
// Stop from accessing any child events
e.preventDefault();
e.stopPropagation();
to the end of the dragEventHandler, but this did not work.
I also have 2 boolean values options.drag and options.start. I though I might be able to use them somehow (if the drag has started and is enabled then don't perform the moveToCenter but this didn't work either.
Do anyone have any idea how to get this to work?
Maybe this will help. You can register your events in bubbling or capturing mode, using addEventListener method. It defines orders of processing your events - child -> parent (bubbling), or vice versa (capturing).
http://www.quirksmode.org/js/events_advanced.html
So, if you use addEventListener(event, handler, true), it will use capturing event mode.
Codepen:
http://codepen.io/anon/pen/bZKdqV?editors=1011
divs.forEach(function (div) {
div.addEventListener('click', function(e) {
e.stopPropagation();
console.log('parent');
}, true);
});
Be aware of browser support (IE9+). All modern browsers - yes, of course.
http://caniuse.com/#search=addeventlistener
Update
So it turned out to be easier than first approach. (no need for capturing)
Check out codepen:
http://codepen.io/anon/pen/QExjzV?editors=1010
Changes from your sample:
At the beginning of moveToCenter: function(e, options, animate) function
if (options.started) {
return;
}
In if (['mouseup', 'mouseleave'].indexOf(e.type) > -1):
setTimeout(function() {
options.started = false;
} , 100);
instead of
options.started = false;
Hope this helps.

Detecting when clicking anywhere outside of element when the clicked element has been removed from the DOM?

I have a notifications dropdown menu that should be closed when you click anywhere outside of it. The following code was working great until I ran into a new situation:
$(document).click(function(e) {
var target = e.target;
if (!$(target).is('.notification-area') && !$(target).parents().is('.notification-area')) {
$('.notification-area .flyout').removeClass('flyout-show');
}
});
However (and I'm using Backbone if that's relevant), some elements cause part of the menu to re-render. That is to say: remove and rebuild a part of the DOM.
Obviously you can't tell where an element is within the DOM if it's already been removed. So now, if there's a click that causes part of that view to re-render then that bit of code that checks the parents() of the element returns no parents.
Then I thought I might be able to solve it by checking if the length of parents() is greater than 0.
...
if (!$(target).is('.notification-area')
&& !$(target).parents().is('.notification-area')
&& $(target).parents().length > 0)
...
And this works but I wonder what side effects it could have. Is this the best way to do this?
Hope I understood your question correct. You want some simple way of not shutting the notification area if clicked upon it. But close it when clicked on body?
One way to do these kind of things is somewhat like this.
mouseOverArea = false; // This will be globally set, right away
$('.notification-area').mouseenter(function(){
mouseOverArea = true;
}).mouseleave(function(){
mouseOverArea = false;
});
And then when you click on body or whatever, you simply check if mouseOverArea == false... If so, close the notification box, otherwise return false, e.preventDefault(); or whatever fits your coding.
You can simplify this using closest() since it includes both the target and ancestors.
It turns :
!$(target).is('.notification-area') && !$(target).parents().is('.notification-area')
Into a simpler to read:
!$(target).closest('.notification-area').length
reference: closest() docs

Jquery on mousedown not working on dynamically generated elements

So i'm trying to create a js/css "wave game" like tower defense ones.
When all the pre-generated enemys from first wave are dead, it spawns the second wave and so on.
So far so good.
The problem is that i just can't attack mobs dynamically spawned within second wave.
I used to try .live() in similar cases, but its deprecated, so i'm trying .on(), as instructed
$('.enemy').on('mousedown' , function(event) {
//attack code
}
Its working fine for initial mobs (1st wave) but it still just not working on dynamic mobs (>= 2nd wave)
Help, guys, please?
You need to specify an element that is already there when the DOM is created. In the parameters, you specify the elements you want to add the mousedown method. By simply assigning $('.enemy'), it will attach the method to those that are already present in the DOM.
$('body').on('mousedown', '.enemy', function(event) {
//attack code
}
As Wex mentioned in the comments, instead of writting $('body') you should use the container's name (the container which wraps the .enemy elements. This way, when a .enemy element is added, the event doesn't need to bubble all the way up to the body tag.
The binding '.on()' works only with the content that created earlier then the script ran.
So one solution could be you bind the event to the parent element.
$('.PARENT_ELEMENT').on('mousedown', '.enemy', function(event){
// your code here
}
That should do it.
I made this google like drop down suggestions search box and I faced a problem similar to yours where there was suggestions disappearing before the re-direct happened. I overcame it by using and modifing vyx.ca answer:
var mousedownHappened = false;
var clicked_link;
$("#search-box").blur(function(e) {
if (mousedownHappened)// cancel the blur event
{
mousedownHappened = false;
window.location.href = clicked_link;
} else {
// no link was clicked just remove the suggestions box if exists
if ($('#search-btn').next().hasClass('suggestions')) {
$(".suggestions").remove();
}
}
});
//attaching the event to the document is better
$(document).on('mousedown', '.suggestions a', function() {
clicked_link= $(this).attr('href');
mousedownHappened = true;
});

Enable and disable jquery knob dynamically

I'm using the excellent jQuery knob plugin. However, I need to dynamically enable/disable the element depending on user input. There is support for having a disabled state on page load which have the effect that no mouse (or touch) events are bound to the canvas element. Does anyone know how to resolve this issue, that is, how to (after page load) bind and unbind these mouse event listeners?
Ideally I would like to do something like this (on a disabled knob)
$('.button').click(function() {
$('.knob').enable();
});
Edit:
I ended up rewriting the source which binds/unbinds the mouse and touch events. The solution is not perfect so I leave the question open if someone perhaps have a better (cleaner) solution.
html
<input class="knobSlider" data-readOnly="true">
<button id="testBtn">clickHere</button>
script
in doc ready,
$(".knobSlider").knob();
$("#testBtn").click(function(){
$(".knobSlider").siblings("canvas").remove();
if($(".knobSlider").attr("data-readOnly")=='true'){
$(".knobSlider").unwrap().removeAttr("data-readOnly readonly").data("kontroled","").data("readonly",false).knob();
}
else{
$(".knobSlider").unwrap().attr("data-readOnly",true).data("kontroled","").data("readonly",true).knob();
}
});
For reference you can use my jsfiddle link > http://jsfiddle.net/EG4QM/ (check this in firefox, because of some external resource load problem in chrome)
If someone doesn't like how the accepted answer destroys and recreates the internal canvas element, then checkout my approach:
https://jsfiddle.net/604kj5g5/1/
Essentially, check the draw() implementation (I also recommend listening on value changes in the draw method instead of the change and release, which work for and click and mousewheel events respectively, which imo is inconvenient).
var $input = $("input");
var knobEnabled = true;
var knobPreviousValue = $input.val();
$input.knob({
draw: function () {
if (knobPreviousValue === $input.val()) {
return;
}
if (!knobEnabled) {
$input.val(knobPreviousValue).trigger("change");
return;
}
knobPreviousValue = $input.val();
console.log($input.val());
},
});
Try this to disable the control.
I'm still trying to find a way to enable it back
$("#btnDisable").click(function(){
$("#knob").off().prev().off();
});

What's the best way of constantly resizing elements with the mouse?

What's the best way of constantly resizing elements using clicking and holding a resize image in the bottom-right corner of the element? Is there a specific empty element that has resizing built in or a style to use that would be better than using a while loop in JavaScript?
Here you go man:
http://jsfiddle.net/d9hsG/
function c(a){console.log(a)}
function coords(el){
var curleft, curtop;
curleft=curtop=0;
do{
curleft+=el.offsetLeft;
curtop+=el.offsetTop;
} while(el=el.offsetParent);
return [curleft,curtop];
}
Resizer = {
attach: function(el,minh,minw){
var rs=el.resizer=el.getElementsByClassName('drag')[0];
rs.resizeParent=el;
if(minh==undefined){
el.minh=rs.offsetHeight*2;
}
if(minw==undefined){
el.minw=rs.offsetWidth*2;
}
rs.onmousedown = Resizer.begin;
},
begin: function(e){
var el=Resizer.el=this.resizeParent;
var e=e||window.event;
this.lastx=e.clientX;
this.lasty=e.clientY;
document.onmousemove=Resizer.resize;
document.onmouseup=Resizer.end;
return false;
},
resize: function(e){
var e = e || window.event;
var x,y,mx,my,el,rs,neww,newh;
el=Resizer.el;
rs=el.resizer;
mx=e.clientX;
my=e.clientY;
neww=(el.clientWidth-(rs.lastx-mx));
newh=(el.clientHeight-(rs.lasty-my));
if(neww>=el.minw){
el.style.width=neww+'px';
rs.lastx=mx;
}
else{
rs.lastx-=parseInt(el.style.width)-el.minw;
el.style.width=el.minw+'px';
}
if(newh>=el.minh){
el.style.height=newh+'px';
rs.lasty=my;
}
else{
rs.lasty-=parseInt(el.style.height)-el.minh;
el.style.height=el.minh+'px';
}
return false;
},
end: function(){
document.onmouseup=null;
document.onmousemove=null;
}
};
window.onload=function(){
Resizer.attach(document.getElementsByClassName('resize')[0]);
}
Your HTML needs to look like:
<div class="resize"><
div class="drag"></div>
</div>
Neither one needs to be a div, but the resizeable one's class needs to be "resize" and the draggable element's class needs to be "drag".
Attach it with:
Resizer.attach(element);
...where element is the one to be resized.
Works on multiple elements, as shown in the jsfiddle. You can also pass in a minimum height and minimum width. If you don't, it automatically makes them twice the height of the draggable element.
It currently does have a problem when you're scrolled all the way down. I'm not sure how to counter it, but I'll work on it more later.
The general approach goes something like this:
When onmousedown fires on the resize target, start tracking onmousemove
When onmousemove fires, resize the element
When onmouseup fires, clear the onmousemove handler
So basically you just respond to events, there are no while loops or anything involved.
It can be somewhat tricky to accomplish so that it works nicely, so I would suggest seeing if there's a JS library you could use. A pretty simple way to get this behavior would be to use jQuery UI's resizable component

Categories

Resources