i have code to download image:
and i have function to check double click from mobile devices:
var touchtime = 0;
$('.download-img').on('click', function() {
if(touchtime == 0) {
//set first click
touchtime = new Date().getTime();
} else {
//compare first click to this click and see if they occurred within double click threshold
if(((new Date().getTime())-touchtime) < 800) {
//double click occurred
alert("double clicked");
touchtime = 0;
} else {
//not a double click so set as a new first click
touchtime = new Date().getTime();
}
}
});
how i can join this 2 part of codes, to make download image from double click, but not single
Here is what I came up with. Though definitely check into that dblclick event MrCode mentioned in his answer.
$('.download-img').on('click', function(e){
var $link = $(this);
//if the time now minus the time stored on the link, or 0 if there is not one, is less than 800, it's valid
if ( Date.now() - ($link.data('touchtime') || 0) < 800 ) {
console.log('double click');
} else {
//time did not exist, or it exceeded the 800 threshold, set a new one
$link.data('touchtime', Date.now());
//prevent the click
e.preventDefault();
}
});
If you capture the event argument, you can call e.preventDefault() when it's a single click.
$('.download-img').on('click', function(e) {
// ^ capture the event
if(touchtime == 0) {
//set first click
touchtime = new Date().getTime();
e.preventDefault();
} else {
...
}
});
You could also use the dblclick event instead of rolling your own double click logic.
Related
I have a simple html page with an input field and I want the input field to register input only after a key was held down for 0.5 second. In other words, in order for a character to be registered, the user has to hold it down for at least 0.5 seconds.
I have tries the following code and works ok for desktop, but when I tried it on iOS and Android it didn't work. My guess is that the keydown function is fired only when the user releases the key since the soft keyboard has some type of special behaviour when held down.
This is the html
<h1 id="hello">Hello</h1>
<input type="text" id="Box">
and this is the script
var downTime = 0;
var currKeycode = 0;
var allowed = ['KeyA','KeyB','KeyC','KeyD','KeyE','KeyF','KeyG','KeyH','KeyI','KeyJ','KeyK', 'KeyL', 'KeyM', 'KeyN', 'KeyO', 'KeyP','KeyQ','KeyR', 'KeyS','KeyT','KeyU','KeyV', 'KeyW','KeyX', 'KeyY', 'KeyZ']
document.getElementById("Box").addEventListener('keydown', function(e) {
if (allowed.includes(e.code)) {
e.preventDefault();
document.getElementById('hello').innerHTML = e.code
if (currKeycode == e.code && downTime != 0) {
var curTime = new Date();
if (curTime - downTime > 100) {
document.getElementById("Box").value = document.getElementById("Box").value + e.key;
downTime = 0;
}
} else {
downTime = new Date();
currKeycode = e.code;
}
console.log("hello " + e.code);
}
});
document.getElementById("Box").addEventListener('keyup', function(e) {
if (allowed.includes(e.code)) {
var curr = new Date();
if (curr - downTime > 100) {
document.getElementById("Box").value = document.getElementById("Box").value + e.key;
}
console.log("bye " + e.code);
}
downTime = 0;
});
Is there a solution to this problem?
Thanks.
EDIT :
I used the line
document.getElementById('hello').innerHTML = e.code
To check when the keydown method was called, and it was only called after I released the key. (Only when testing on mobile).
Although it's not related to JavaScript specifically, but apparently according to the Android Docs, keyDown, in general, is fired if the key is continually pressed.
So simply
var startedDown, timeWhenStarted;
test.onkeydown = e => {
if(!startedDown) {
timeWhenStarted = Date.now();
startedDown = true
}
if(Date.now() - timeWhenStarted < 500) {
e.preventDefault();
return false;
}
startedDown = false;/*if you want the
delay to apply for every key press,
if you just want it to apply for every time
the box is focused, then put this line in
a onblur event instead to reset it, or in
a keyup event if you want the delay to happen
every time one starts typing after holding down
a key*/
};
<input id=test>
I have the following jquery event handling function:
$('.target').on('dblclick', function() {
//respond to double click event
});
My issue is that this event handler doesn't work on touch devices (iPhone, iPad...). Can anyone recommend a reliable alternative to dblclick that works on touch devices and still allows comfortable double click use on full size devices?
I ended up building a custom double click function that will work on both mobile and desktop:
var touchtime = 0;
$(".target").on("click", function() {
if (touchtime == 0) {
// set first click
touchtime = new Date().getTime();
} else {
// compare first click to this click and see if they occurred within double click threshold
if (((new Date().getTime()) - touchtime) < 800) {
// double click occurred
alert("double clicked");
touchtime = 0;
} else {
// not a double click so set as a new first click
touchtime = new Date().getTime();
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div class="target">Double click me</div>
Alternatively, here is the JSfiddle Demo.
Add this to your index.html
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
I found the mobile zoom function would throw off Jquery's dblclick. Basically it says your viewport wont change effectively shutting off the zoom. This works for me on my Nexus 5 running Chrome.
I know the question has been answered but thought it would be worth putting the solution I use all the time, cheers:
var doubleClicked = false;
$('.target').on('click', function() {
if (doubleClicked) {
//do what you want to do on double click here
}
doubleClicked = true;
setTimeout(() => {
doubleClicked = false;
}, 300);
});
You can bind multiple event listeners on the element and use jQuery's tap event for the touch devices.
$( ".target" ).on({
dbclick: function() {
//do stuff
}, touch: function() {
//do the same stuff
}
});
Thanks for the solution - the only thing I did was add a timeout so that they could be treated as separate events
var touchtime = 0;
var delay = 800;
var action = null;
$(".target").on("click", function() {
/*Double Click */
if((new Date().getTime() - touchtime) < delay){
clearTimeout(action)
alert('dbl');
touchtime=0;
}
/* Single Click */
else{
touchtime = new Date().getTime();
action = setTimeout(function(){
alert('single');
},delay);
}
}));
Although I haven't tested it, might also be worth adding the following to a header section of any HTML <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/> as per: To "user-scalable=no" or not to "user-scalable=no"
The marked answer of #JRulle seems to work only for a single object, if u have many instances with the same class they will be considered as a single object
see the exampleFiddle example
My solution seems to work in cases like that
var touchtime = 0;
$('.target').on('click', function() {
if (touchtime == 0) {
touchtime = new Date().getTime();
} else {
if (((new Date().getTime()) - touchtime) < 800) {
alert("double clicked");
touchtime = 0;
} else {
touchtime = 0;
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<p class="target">click me!</p>
<p class="target">then click me!</p>
click link
Multiple targets with own doubleclick counter. The accepted solution has 2 bugs, that are fixed here:
If you click on target and click outside and click on target again within 800 ms, then the doubleclick event fires.
If you have multiple targets, click on different targets within 800 ms, and the doubleclick event fires.
$(document).on("click", function(e)
{
var MAX_DELAY_IN_MS = 800;
var current_time = new Date();
var targets = $(".target");
if ((typeof last_target == "undefined") ||
(last_target == 0))
{
last_target = e.target;
last_click = current_time;
}
else
{
if ((last_target == e.target) &&
((targets.is(e.target) == true) ||
(targets.has(e.target).length !== 0)) &&
(current_time - last_click < MAX_DELAY_IN_MS))
{
alert("double clicked");
}
last_target = 0;
last_click = 0;
}
});
div{display:inline-block; width:30px; height:30px; margin:5px;}
.target{background-color:lime;}
.no_target{background-color:orange;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div class="target"></div>
<div class="target"></div>
<div class="no_target"></div>
<div class="target"></div>
Programmatically all of the answers given above are fine.
When you double click on mouse button it's just the mass off your finger involved,
so it can be fast...
On the other hand when tapping touch screen usually much larger physical mass is involved.
Larger mass means slower times .
So my approach is "click two times" instead of double click.
Means a global variable e.g var ClickCounter=0;
Inside the function scope
ClickCounter++;
Check if ClickCounter ==2.
Execute your Code.
Reset counter ClickCounter=0
else return false or execute another code
I have an improvement to the code above, that didnĀ“t detect a doubleclick after a single click:
var touchtime = 0;
$(".target").on("click", function() {
if (((new Date().getTime()) - touchtime) < 500) {
alert("double clicked");
}
touchtime = new Date().getTime();
});
This code detects all doubleclicks. I also reduced the touchtime to 500ms (standard doubleclick-time).
The only way is to detect double touch yourselves. You can do it by persisting last touch event timestamp like below:
if (e.touches.length === 1) {
if (this.lastTouchEventTimeStamp) {
const timeInMillisecondsSinceLastTouch = e.timeStamp - this.lastTouchEventTimeStamp;
if (timeInMillisecondsSinceLastTouch > 80 && timeInMillisecondsSinceLastTouch < 400) {
// double tap will be detected here
this.lastTouchEventTimeStamp = undefined;
const dblClickEvent = new DragEvent('dblclick', {
view: window,
bubbles: true,
cancelable: true
});
e.target.dispatchEvent(dblClickEvent);
}
}
this.lastTouchEventTimeStamp = e.timeStamp;
}
Came across this thread and wanted to supply an updated answer.
function doubleClick(event, callback) {
var touchtime = $(event.target).data("touch-time");
if (touchtime == undefined || touchtime == 0) {
// set first click
$(event.target).data("touch-time", new Date().getTime());
} else {
// compare first click to this click and see if they occurred within double click threshold
if (((new Date().getTime()) - touchtime) < 800) {
// double click occurred
callback();
$(event.target).data("touch-time", 0);
} else {
// not a double click so set as a new first click
$(event.target).data("touch-time", new Date().getTime());
}
}
}
It can then be used as follows:
$(selector).click(function(event){
doubleClick(event, function(){
console.log("Hello World");
});
});
This uses the Data Attribute versus a global variable to get/set the Touch Time.
The standard dblclick should work in modern mobile browsers.
This is it... in CoffeeScript
onDblClick = -> "...your function to be fired..."
dbl_click = null
$(element).on 'mousedown', ->
onDblClick() if dbl_click
dbl_click = true
setTimeout () ->
dbl_click = false
, 250
You need to enter "return false" to the end of the function like below
var touchtime = 0;
$('.dbclickopen').click(function() {
if(touchtime == 0) {
//set first click
touchtime = new Date().getTime();
} else {
//compare first click to this click and see if they occurred within double click threshold
if(((new Date().getTime())-touchtime) < 800) {
//double click occurred
touchtime = 0;
window.location = this.href;
} else {
//not a double click so set as a new first click
touchtime = new Date().getTime();
}
}
return false;
});
I need to count the number of clicks on a piece of content - after which, I need to run a certain function.
I can't run the function on every click, only after the user finishes their desired clicks.
The amount of clicks needs to be 1, 2, or 3 and above, where I only want to do something on one or two clicks, and ignore anything else.
Note I only need to run the function after the clicks, then reset the counter.
I've tried the following, but it logs 'single' after every click.
var clicks = 0;
$(controller).click(function() {
var elem = this, $elem = jQuery(elem), clicks = $elem.data('clicks') || 0;
clicks += 1;
// Reset triple click counter if no click is made within 500ms
setTimeout(function() {
clicks = 0;
}, 500);
setTimeout(function() {
if (clicks >= 3) {
console.log("triple or more");
}
if (clicks === 2) {
console.log("double");
}
if (clicks === 1) {
console.log("single");
}
}, 200);
});
Here is a JSBin example
It's a little hard to see what you want to happen after 3 clicks, do you want to trigger triple clicks for each of them or not.
I created a version that you might want to look at: http://jsbin.com/dutilojujowa/5/edit
The ideas are:
Save all the click counter data into the data attribute instead of relying on scope - I find that easier.
Throttle your reset counter, otherwise multiple clicks can be handled very strangely
Throttle your action counter, or you might get multiple actions accidentally!
Make sure you set $elem.data('clicks') to 1 at some point, or it won't work.
You need to update $elem.data('clicks') at the end of your function. See http://css-tricks.com/snippets/jquery/triple-click-event/
Can you try following code:
var totalCount;
var intervalVar;
var ShowResultVar;
function HandleClicks() {
totalCount = totalCount + 1;
}
function ShowResult() {
if(totalCount == 0)
{
console.log("No Clicks");
}
else if (totalCount == 1)
{
console.log("One Click");
}
else if(totalCount == 2)
{
console.log("Two Clicks");
}
else if (totalCount >2) {
console.log("Three or more Clicks");
}
}
$(document).ready(function () {
totalCount = 0;
$("#myControl").bind("click", HandleClicks);
intervalVar = setInterval(function () {
totalCount = 0;
}, 500);
ShowResultVar = setInterval(function () {
ShowResult();
}, 200);
});
It is working for me. Output is as follows:
No Clicks
No Clicks
No Clicks
No Clicks
No Clicks
No Clicks
No Clicks
No Clicks
No Clicks
No Clicks
One Click
Two Clicks
One Click
Two Clicks
No Clicks
One Click
Two Clicks
No Clicks
One Click
Two Clicks
Two Clicks
Three or more Clicks
One Click
One Click
No Clicks
No Clicks
No Clicks
No Clicks
No Clicks
Try this-
$("#content").data('clicks', 0);
$("#content").click(function () {
var elem = this,
$elem = jQuery(elem);
var clicks = $elem.data('clicks') + 1
$elem.data('clicks', clicks);
if (clicks == 1) {//start re-setter and counter when first click
setTimeout(function () {
$elem.data('clicks', 0);
}, 500);
setTimeout(function () {
var clicks = $elem.data('clicks');
if (clicks >= 3) {
console.log("triple or more");
}
if (clicks === 2) {
console.log("double");
}
if (clicks === 1) {
console.log("single");
}
}, 200);
}
});
DEMO
i am trying to write a custom event which should get fire when user click three times on any html node.
i know that i can create even using
var evt = document.createEvent("Event");
evt.initEvent("myEvent",true,true);
but i am not getting how i will capture that three times click event.
I will be appreciated if some one can suggest me the write approach for this.
Thanks!!!
You can create a special event
Code and example - here is your problem solvation :)
Just create a variable that stores the number of clicks.
var clickTimes = 0;
element.addEventListener('click', function(event) {
clickTimes++;
if(clickTimes==3) {
clickTimes = 0;
/* do something like dispatch my custom event */
}
});
This will count the clicks for any specific element and trigger Event on every third click.
$('selector').on('click',function(e){
Event_threshold = 500;
var clicked_times = $(this).data('Event-clicked-times');
if(clicked_times == '')
clicked_times = 0;
if(clicked_times == 0)
$(this).data('Event-first-click-timestamp',e.timeStamp);
clicked_times++;
if(e.timeStamp-$(this).data('Event-first-click-timestamp')<Event_threshold)
{
if(clicked_times == 3)
{
$(this).data('Event-clicked-times',0);
$(this).trigger('Event');
}
else
$(this).data('Event-clicked-times',clicked_times);
}
else
$(this).data('Event-clicked-times',0);
});
EDIT:
Fixed and added threshold control.
You can create iteration variable and check if element was three times clicked.
For example:
var clickTimer = 0;
document.body.addEventListener('click', function() {
clickTimer++;
if(clickTimer == 3) {
clickTimer = 0;
// fire your event
}
}, true);
To make this behavior like dbclick you can compare timestamp with first click.
For example:
var clickTimes = 0;
var fisrtClickTime = 0;
element.addEventListener('click', function(event) {
clickTimes++;
if(clickTimes == 1) {
fisrtClickTime = +new Date();
}
if(clickTimes == 3) {
clickTimes = 0;
firstClickTime = 0;
if((+new Date() - fisrtClickTime) < 1000) {
/* do something like dispatch my custom event */
}
}
});
This works without using external variables, using the HTML5 "data-" attribute for storage, so you will work on multiple elements.
$('#yourLink').click(function() {
window.setTimeout(function() {$(this).data("count",1)},300)
if(typeof $(this).data("count")=='undefined') {
$(this).data("count",1)
}
else {
var myCount = parseInt($(this).data("count"))
myCount++
if(myCount==3) {
alert("3!")
$(this).data("count",0)
}
else {
$(this).data("count",myCount)
}
}
})
I have created a form with malsup's Form Plugin wherein it submits on change of the inputs. I have set up my jQuery script to index drop down menus and visible inputs, and uses that index to determine whether keydown of tab should move focus to the next element or the first element, and likewise with shift+tab keydown. However, instead of moving focus to the first element from the last element on tab keydown like I would like it to, it moves focus to the second element. How can I change it to cycle focus to the actual first and last elements? Here is a live link to my form: http://www.presspound.org/calculator/ajax/sample.php. Thanks to anyone that tries to help. Here is my script:
$(document).ready(function() {
var options = {
target: '#c_main',
success: setFocus
};
$('#calculator').live('submit', function() {
$(this).ajaxSubmit(options);
return false;
});
$(this).focusin(function(event) {
var shiftDown = false;
$('input, select').each(function (i) {
$(this).data('initial', $(this).val());
});
$('input, select').keyup(function(event) {
if (event.keyCode==16) {
shiftDown = false;
$('#shiftCatch').val(shiftDown);
}
});
$('input, select').keydown(function(event) {
if (event.keyCode==16) {
shiftDown = true;
$('#shiftCatch').val(shiftDown);
}
if (event.keyCode==13) {
$('#captured').val(event.target.id);
} else if (event.keyCode==9 && shiftDown==false) {
return $(event.target).each(function() {
var fields = $(this).parents('form:eq(0),calculator').find('select, input:visible');
var index = fields.index(this);
var nextEl = fields.eq(index+1).attr('id');
var firstEl = fields.eq(0).attr('id');
var focusEl = '#'+firstEl;
if (index>-1 && (index+1)<fields.length) {
$('#captured').val(nextEl);
} else if(index+1>=fields.length) {
if ($(this).val() != $(this).data('initial')) {
$('#captured').val(firstEl);
} else {
event.preventDefault();
$(focusEl).focus();
}
}
return false;
});
} else if (event.keyCode==9 && shiftDown==true) {
return $(event.target).each(function() {
var fields = $(this).parents('form:eq(0),calculator').find('select, input:visible');
var index = fields.index(this);
var prevEl = fields.eq(index-1).attr('id');
var lastEl = fields.eq(fields.length-1).attr('id');
var focusEl = '#'+lastEl;
if (index<fields.length && (index-1)>-1) {
$('#captured').val(prevEl);
} else if (index==0) {
if ($(this).val() != $(this).data('initial')) {
$('#captured').val(lastEl);
} else {
event.preventDefault();
$(focusEl).select();
}
}
return false;
});
}
});
});
});
function setFocus() {
with (document.calculator)
var recap = document.getElementById(recaptured.value);
if (recap!=null) {
setTimeout(function() {
if (recap.getAttribute('type')=='text') {
recap.select();
} else {
recap.focus();
}
}, 100 );
}
}
Edit #1: I made a few minor changes to the code, which has brought me a little closer to my intended functionality of the script. However, I only made one change to the code pertaining to the focus: I tried to to disable the tab keydown when pressed on the last element (and also the shift+tab keydown on the first element) in an attempt to force the focus on the element I want without skipping over it like it has been doing. This is the code I added:
$(this).one('keydown', function (event) {
return !(event.keyCode==9 && shiftDown==true);
});
This kind of works. After the page loads, If the user presses tab on the last element without making a change to its value, the focus will be set to the second element. However, the second time the user presses tab on the last element without making a change to its value, and every subsequent time thereafter, the focus will be set to the first element, just as I would like it to.
Edit #2: I replaced the code in Edit #1, with code utilizing event.preventDefault(), which works better. While if a user does a shift+tab keydown when in the first element, the focus moves to the last element as it should. However, if the user continues to hold down the shift key and presses tab again, focus will be set back to the first element. And if the user continues to hold the shift key down still yet and hits tab, the focus will move back to the last element. The focus will shift back and forth between the first and last element until the user lifts the shift key. This problem does not occur when only pressing tab. Here is the new code snippet:
event.preventDefault();
$(focusEl).focus();
You have a lot of code I didn't get full overview over, so I don't know if I missed some functionality you wanted integrated, but for the tabbing/shift-tabbing through form elements, this should do the work:
var elements = $("#container :input:visible");
var n = elements.length;
elements
.keydown(function(event){
if (event.keyCode == 9) { //if tab
var currentIndex = elements.index(this);
var newIndex = event.shiftKey ? (currentIndex - 1) % n : (currentIndex + 1) % n;
var el = elements.eq(newIndex);
if (el.attr("type") == "text")
elements.eq(newIndex).select();
else
elements.eq(newIndex).focus();
event.preventDefault();
}
});
elements will be the jQuery object containing all the input fields, in my example it's all the input fields inside the div #container
Here's a demo: http://jsfiddle.net/rA3L9/
Here is the solution, which I couldn't have reached it without Simen's help. Thanks again, Simen.
$(document).ready(function() {
var options = {
target: '#c_main',
success: setFocus
};
$('#calculator').live('submit', function() {
$(this).ajaxSubmit(options);
return false;
});
$(this).focusin(function(event) {
$('#calculator :input:visible').each(function (i) {
$(this).data('initial', $(this).val());
});
return $(event.target).each(function() {
$('#c_main :input:visible').live(($.browser.opera ? 'keypress' : 'keydown'), function(event){
var elements = $("#calculator :input:visible");
var n = elements.length;
var currentIndex = elements.index(this);
if (event.keyCode == 13) { //if enter
var focusElement = elements.eq(currentIndex).attr('id');
$('#captured').val(focusElement);
} else if (event.keyCode == 9) { //if tab
var newIndex = event.shiftKey ? (currentIndex - 1) % n : (currentIndex + 1) % n;
var el = elements.eq(newIndex);
var focusElement = el.attr('id');
if ($(this).val() != $(this).data('initial')) {
$('#captured').val(focusElement);
} else if ((currentIndex==0 && event.shiftKey) || (currentIndex==n-1 && !event.shiftKey)) {
event.preventDefault();
if (el.attr('type')=='text') {
$.browser.msie ? "" : $(window).scrollTop(5000);
el.select().delay(800);
} else {
$.browser.msie ? "" : $(window).scrollTop(-5000);
el.focus().delay(800);
}
} else if (el.is('select')) {
event.preventDefault();
if (el.attr('type')=='text') {
el.select();
} else {
el.focus();
}
}
}
});
});
});
});
function setFocus() {
with (document.calculator)
var recap = document.getElementById(recaptured.value);
if (recap!=null) {
setTimeout(function() {
if (recap.getAttribute('type')=='text') {
recap.select();
} else {
recap.focus();
}
}, 1 );
}
}
I put my files available to download in my live link: http://www.presspound.org/calculator/ajax/sample.php