I am trying to add an event handler to a div that has an image inside of the div. My problem is that the event only works if you double click outside the div right next to it. When you double click the picture inside the div it doesnt not trigger the event. How do I make it so that the event works both ways?
html
<div id="placeholder">
<a href="http://google.com" target="_blank">
<img src="http://www.fat-animals.com/wp-content/uploads/2009/03/11.jpg" alt="" />
</a>
</div>
javascript
var pic;
pic = document.getElementById("placeholder");
pic.ondblclick = function() {
pic.innerHTML = "blocked!";
}
demo
http://jsfiddle.net/9DWrN/
check this fiddle
http://jsfiddle.net/unloco/9DWrN/3/
var pic = document.getElementById("placeholder");
var clicked = false;
pic.onclick = function() {
if(clicked) {
pic.innerHTML = "blocked!";
} else {
clicked = true;
}
setTimeout(function(){
clicked = false
}, 333); //detect fast clicks (333ms)
}
Your current solution actually works, it just doesn't seem like it, since you are redirected to a new page.
If you have Chrome (Firefox too probably, maybe even IE 8+), double middle click on the image (opens in new tab/window). Your event will still get fired. You can then proceed to preventDefault on these events.
Using a double click event is not the best idea to prevent malicious clicks though, as the double click event will only get thrown every two clicks. While a client side validation is bad to prevent malicious clicks anyways, its best to use a click event and check with a timer (i.e. throttle the event to a maxmimum of once every 200 milliseconds, or only allow it if there was not a previous click within the previous 200 milliseconds.
And what about changing pic.innerHTML at onclick?
See http://jsfiddle.net/4Kecd/
var = document.getElementById("placeholder");
pic.onclick = function() {
pic.innerHTML = "blocked!";
alert('The link has been blocked');
}
Even if you delete the link, it will be followed that time.
See http://jsfiddle.net/4Kecd/1/ too.
You can do...
var pic1 = document.getElementById("placeholder1"),
clicked1=false;
pic1.onclick = function() {
if(clicked1){
alert("The link has been deleted. You can't follow the link twice!");
}else{
pic1.innerHTML = pic2.getElementsByTagName('a')[0].innerHTML;
alert('The link has been deleted.\nHowever, the new tab will be opened when you accept this alert.');
clicked1=true;
}
}
...if you want to delete the link but you want the image.
Or you can just disable the link:
var pic2 = document.getElementById("placeholder2"),
clicked2=false;
pic2.onclick = function(e) {
var a=pic2.getElementsByTagName('a')[0];
if(clicked2){
alert("The link has been disabled. You can't follow the link twice!");
a.href="#";/* Nonsense since we have disabled the link,
but we want to ensure that the link isn't followed*/
}else{
clicked2=true;
a.onclick=function(){return false;}
alert('The link has been disabled.\nHowever, the new tab will be opened when you accept this alert.');
}
}
Note: UnLoCo's solution is good but its problem is that it doesn't prevent us from following the link.
Instead, you can disable the link at first click and enable it after some seconds:
var pic = document.getElementById("placeholder"),
clicked=false;
pic.onclick = function(e) {
var a=pic.getElementsByTagName('a')[0];
if(clicked){
alert("The link has been disabled. You can't follow the link twice!");
a.href="#";
}else{
clicked=true;
a.onclick=function(){return false;}
if(!a.getAttribute('data-href')){
a.setAttribute('data-href',a.href);
}
alert('The link has been disabled.\nHowever, the new tab will be opened when you accept this alert.');
setTimeout(function(){enableLink(a);},5000);
}
}
function enableLink(a){
a.href=a.getAttribute('data-href');
a.onclick=function(){return true;}
clicked=false;
}
See it here: http://jsfiddle.net/4Kecd/2/
Related
In JavaScript, is it possible to distinguish between beforeunload events that were triggered by the user closing a browser tab vs clicking a mailto link?
Basically, I would like to do this:
window.addEventListener("beforeunload", function (e) {
if(browserTabClosed) {
// Do one thing
}
else if (mailtoLinkClicked) {
// Do a different thing
}
}
Found a solution by looking at the event (e below) that gets passed in:
window.addEventListener("beforeunload", function (e) {
// We can use `e.target.activeElement.nodeName`
// to check what triggered the passed-in event.
// - If triggered by closing a browser tab: The value is "BODY"
// - If triggered by clicking a link: The value is "A"
const isLinkClicked = (e.target.activeElement.nodeName === "A");
// If triggered by clicking a link
if (isLinkClicked) {
// Do one thing
}
// If triggered by closing the browser tab
else {
// Do a different thing
}
}
The beforeunload method has an unstable behaviour between browsers, the reason is that browser implementations try to avoid popups and other malicious code runned inside this handler.
There is actually no general (cross-browser) way to detect what triggered the beforeunload event.
Said that, in your case you could just detect a click on the window to discriminate between the two required behaviours:
window.__exit_with_link = false;
window.addEventListener('click', function (e) {
// user clicked a link
var isLink = e.target.tagName.toLowerCase() === 'a';
// check if the link has this page as target:
// if is targeting a popup/iframe/blank page
// the beforeunload on this page
// would not be triggered anyway
var isSelf = !a.target.target || a.target.target.toLowerCase() === '_self';
if (isLink && isSelf) {
window.__exit_with_link = true;
// ensure reset after a little time
setTimeout(function(){ window.__exit_with_link = false; }, 50);
}
else { window.__exit_with_link = false; }
});
window.addEventListener('beforeunload', function (e) {
if (window.__exit_with_link) {
// the user exited the page by clicking a link
}
else {
// the user exited the page for any other reason
}
}
Obviously it is not the proper way, but still working.
At the same way, you could add other handlers to check other reasons the user left the page (eg. keyboard CTRL-R for refresh, etc.)
Adding Event Listener
function Solitaire() {
this.table.addEventListener("click", this.handleClick.bind(this));
this.table.addEventListener("dblclick", this.handleDoubleClick.bind(this));
}
Handling Event
Solitaire.prototype.handleDoubleClick = function(event) {
console.log("DoubleClick");
};
Solitaire.prototype.handleClick = function(event) {
console.log("Click");
};
Expected output (in console) on a double click event
DoubleClick
But the output I get in console:
Click
Click
DoubleClick
I don't know about easeljs, but I can tell you about how it is done in jQuery, where you need to "hack" it to make it actually work.
var DELAY = 500;
$('#my_element').on('click', function(e){
++clicks; // Count the clicks
if(clicks === 1){
// One click has been made
var myTimerToDetectDoubleClick = setTimeout(function(){
console.log('This was a single click');
doStuffForSingleClick();
clicks = 0;
}, DELAY);
} // End of if
else{
// Someone is clicking pretty damn fast, they probably mean double click :p
clearTimeout(myTimerToDetectDoubleClick);
doStuffForDoubleClick();
clicks = 0;
}
}).on('dblclick', function(evt){
evt.preventDefault(); // cancel system's default double click
});
The basic essence will remain the same for event handling for easeljs. You can imitate this behaviour accordingly there.
I have a javascript confirm dialog popping up, but when I tap 'Cancel', then after the dialog closes, tap anywhere on the screen, the dialog pops up again. It only happens the one extra time, then you can tap on the page again without the dialog popping up.
I'm only seeing this on iPhone/iPad running iOS 5.0.1. I don't have an iOS 6 device, so I'm not sure it's happening there.
Here's the code I'm using:
$(bpm.remoteAppDivName).on('tap', 'a.delete-pending-payment', function(event) {
if (isJQMGhostClick(event)) { return false; }
var deleteGlobalPaymentURL = $(this).attr('href');
var confirmMsg = confirm ("Are you sure you want to do that?");
if (confirmMsg === true){
window.location = '/index.htm';
}
event.preventDefault();
return false;
});
var lastclickpoint, curclickpoint;
var isJQMGhostClick = function(event){
curclickpoint = event.clientX+'x'+event.clientY;
var ret=false;
if (lastclickpoint === curclickpoint) {
ret=true;
} else {
ret=false;
}
lastclickpoint = curclickpoint;
return ret;
}
Here's a link to the problem page: http://www.5280skateparks.com/dev/confirmBug.htm
Any help would be extremely appreciated.
UPDATE: I just confirmed that it's happening on iOS 6.0.1 as well.
This is the jQuery Mobile "Ghost Click" discussed in some detail here and here. On the forum page, a solution was proposed, which I have reproduced below with a small bug fix:
var lastclickpoint, curclickpoint;
var isJQMGhostClick = function(event){
curclickpoint = event.clientX+'x'+event.clientY;
var ret=false;
if (lastclickpoint === curclickpoint) {
ret=true;
} else {
ret=false;
}
lastclickpoint = curclickpoint;
return ret;
}
I have modified this code slightly to not always expect a pair of clicks. This function now works correctly in the case of 0 ghost clicks and more than 2 ghost clicks. You can use it by checking isJQMGhostClick(event) at the beginning of your tap handler and ignoring the event if the isJQMGhostClick function returns true.
I'm writing js for a status update system to be used on various pages throughout a app that I'm working. I am really just starting to get more comfortable with javascript so it has been somewhat of a challenge to get to the point where I have everything now.
The status system is basically a facebook clone. For the most part everything is supposed to function the way that facebook's status updates and status comments do. The intended behavior is that when the user clicks in the status textarea, the div under the status textarea slides out revealing the submit button as well as some other checkboxes.
If the user clicks anywhere else on the page except a link or any element that has the class prevent_slideup the div slides up hiding the submit button and any checkboxes.
I'm using a document.body click function to determine what the user clicked on so I know which form elements to hide if I should even hide them. I do not want this slideup to take place on a textarea if that textarea has focus or the user is selecting a checkbox that goes with that form. Hence the prevent_slideup class. I also do not want to bother running the slideup logic if the user has clicked on a link. I'd prefer they just leave the page without having to wait for the animation.
The code that I was using to accomplish this task can be found in the $(document.body).click(function (e) section below where I'm doing a .is('a') check on the event target.
This code works as expected in chrome and firefox, however in ie when a link is clicked for the first time it seems that the element stored in var target is actually a div instead of an anchor. What ends up happening is that the submit div slides up and the user is not taken to the link that they just clicked on. If a link is clicked a second time the user is taken to the page as you would expect.
It seems to me that there's some kind of a lag in ie as to what the current event being fired is.
The entire status module is working other than this one strange ie bug regarding the users click on the link not being carried out the first time that they click a link after opening the status textarea. Does anything jump out in this script that would explain this behavior or does anyone have any other advice?
Thanks in advance for your help.
$(document).ready(function(){
$("textarea.autoresize").autoResize();
});
$(document.body).click(function (e){
var target = e.target || e.srcElement;
console.log(target);
console.log($(target).is('a'));
if($(target).hasClass('prevent_slideup') || $(target).is('a'))
{
return true;
}
else
{
var active_element = document.activeElement;
var active_status_id = $(active_element).attr('data-status_id');
var active_has_data_status_id = (typeof active_status_id !== 'undefined' && active_status_id !== false) ? true : false;
$('textarea').each(function(){
if($(this).hasClass('status_comment_textarea'))
{
var status_id = $(this).attr('data-status_id');
if($('#comment_textarea_'+status_id).val() === '' && (!active_has_data_status_id || active_status_id !== status_id))
{
hide_status_comment_submit(status_id);
}
}
else if($(this).attr('id') === 'status_textarea')
{
if($('#status_textarea').val() === '' && $(active_element).attr('id') !== 'status_textarea')
{
$('#status_textarea').html($("#status_textarea").attr('placeholder'));
hide_status_submit();
}
}
});
return true;
}
});
$("#status_textarea").live('click', function(){
if($('#status_textarea').val() === $("#status_textarea").attr('placeholder'))
{
$('#status_textarea').html('');
}
show_status_submit();
return false;
});
$(".comment_toggle").live('click', function(){
var status_id = $(this).attr('data-status_id');
show_status_comment_submit(status_id);
return false;
});
$(".status_comment_submit").live('click', function(){
var status_id = $(this).attr('data-status_id');
$('#status_comment_submit_wrapper_'+status_id).addClass('status_comment_submit_successful');
return false;
});
$(".show_hidden_comments").live('click', function(){
var status_id = $(this).attr('data-status_id');
$('#status_hidden_comments_'+status_id).show();
$(this).hide();
return false;
});
function hide_status_submit()
{
$("#status_textarea").removeAttr('style');
$("#status_textarea").blur();
$("#status_block").removeClass('padding_b10');
$("#status_submit_wrapper").slideUp("fast");
return false;
}
function show_status_submit()
{
if ($("#status_submit_wrapper").is(":hidden"))
{
$("#status_block").addClass('padding_b10');
$("#status_submit_wrapper").slideDown('fast');
}
return false;
}
function hide_status_comment_submit(status_id)
{
if(!$('#status_comment_submit_wrapper_'+status_id).is(":hidden"))
{
$('#status_comment_submit_wrapper_'+status_id).hide();
$('#fake_comment_input_'+status_id).show();
$('#comment_textarea_'+status_id).removeAttr('style');
}
return false;
}
function show_status_comment_submit(status_id)
{
if($('#status_comment_submit_wrapper_'+status_id).is(":hidden"))
{
$('#fake_comment_input_'+status_id).hide();
$('#status_comment_submit_wrapper_'+status_id).show();
$('#comment_textarea_'+status_id).focus();
}
return false;
}
function status_comment_submit_successful()
{
hide_status_comment_submit($('.status_comment_submit_successful').attr('data-status_id'));
$('.status_comment_submit_successful').removeClass('status_comment_submit_successful');
return false;
}
I figured out that there were two main issues with my script...
1.) The document.body function and the #status_textarea live click funtioins were conflicting with each other.
2.) After adding the logic for the #status_textarea function into the document.body function I noticed that the script still didn't quite work as expected in internet explorer unless I had an alert in the function. The problem at this point was that the autoresize plugin that I'm using on the textarea was also conflicting with the document.body function.
I was able to rectify the situation by adding a dummy text input and hiding the status textarea. On click of the dummy text input the status textarea is shown and the the dummy text input is hidden. I have no idea why this worked, but it seems to have solved my problems.
I got a function which checks if some input fields are changed:
var somethingchanged = false;
$(".container-box fieldset input").change(function() {
somethingchanged = true;
});
And a function which waits on window.onload and fires this:
window.onbeforeunload = function(e) {
if (somethingchanged) {
var message = "Fields have been edited without saving - continue?";
if (typeof e == "undefined") {
e = window.event;
}
if (e) {
e.returnValue = message;
}
return message;
}
}
But if I edit some of the fields and hit the save button, the event triggers, because there is a post-back and the fields have been edited. Is there anyway around this, so the event does not fire upon clicking the save button?
Thanks
When I do this pattern I have a showDirtyPrompt on the page. Then whenever an action occurs which I don't want to go through the dirty check I just set the variable to false. You can do this on the client side click event of the button.
The nice thing about this is that there might be other cases where you don't want to prompt, the user you might have other buttons which do other post backs for example. This way your dirty check function doesn't have to check several buttons, you flip the responsability around.
<input type="button" onclick="javascript:showDirtyPrompt=false;".../>
function unloadHandler()
{
if (showDirtyPrompt)
{
//have your regular logic run here
}
showDirtyPrompt=true;
}
Yes. Check to see that the button clicked is not the save button. So it could be something like
if ($this.id.not("savebuttonID")) {
trigger stuff
}