I'm working on a tampermonkey userscript to replace a feature that existed with FireGestures back in Pre-Quantum Firefox. The ability to open all hovered links into new background tabs. So having a combination keypress, which in FG was Ctrl + Right Click and drawing a gesture trail though every link you wanted open. Everything I have so far has been written for me by somebody else so I'm not trying to take credit and I in am way over my head. I don't have the know-how to edit and fix what is needed. This is what I have so far.
(function(delay, t, lnk, clicked) {
//config: delay before click. mouse movement will reset the delay timer.
delay = 1000; //in milliseconds. 1sec = 1000ms
t = 0;
function mousemove() {
clearTimeout(t);
if (lnk) t = setTimeout(clickLink, delay);
}
function clickLink() {
removeEventListener("mousemove", mousemove);
clearTimeout(t);
if (lnk) {
lnk.target = "_blank";
lnk.click();
lnk.target = "";
clicked = true;
}
}
addEventListener("mouseover", function(ev, el, el2) {
el = ev.target;
removeEventListener("mousemove", mousemove);
clearTimeout(t);
while (el) {
if (el.tagName === "A") {
el2 = el;
if (el !== lnk) {
lnk = el;
clicked = false;
addEventListener("mousemove", mousemove);
clearTimeout(t);
t = setTimeout(clickLink, delay);
}
return;
}
el = el.parentNode;
}
if (!el2) {
lnk = null;
clicked = false;
removeEventListener("mousemove", mousemove);
clearTimeout(t);
}
});
})();
There is a couple issues I face.
1. This doesn't require any sort of button combination. It is continually active and will click any link that is hovered over for the specified length of time. I would prefer it to only function when a button combination is pressed, ideally Ctrl + Rightclick. I found a thread dealing with combination keypresses but wouldn't know how to edit it and insert it into the existing script to fit my needs.
document.addEventListener ("keydown", function (zEvent) {
if (zEvent.ctrlKey && zEvent.altKey && zEvent.code === "KeyE") {
// DO YOUR STUFF HERE
}
} );
2. The pop-up blocker in chrome actually prevents these tabs from opening. I don't know if there is any way of remedying this other than turning off the pop-up blocker, but if there was I'd appreciate the help
3. This script opens up tabs in the foreground rather than the background. So opening up a bunch of links on a page wouldn't be possible because it would navigate to the new tab as soon as the first link is clicked. My original idea for fixing this was to just have the script just do a middle-click mouse event over every link it passed over, but I don't even know if that is something that is possible or practical.
I know I am asking a lot but I was just hoping that someone out there that knows what they are doing could help me out by either editing what I already have or writing something out themselves. I appreciate any help provided.
here's my spin on it. This is toggled rather than going on while you are holding onto the keys.
you could had the following to your TamperMonkey script, and when you press "Ctrl + Alt + S", the links on the page are modified and appended a onmouseover event. when you hit the key combination again, the event gets removed from the link. Short and simple.
document.addEventListener('keydown', function (zEvent) {
if (zEvent.ctrlKey && zEvent.altKey && zEvent.code === 'KeyS') {
var links = document.getElementsByTagName('a');
console.log(links.length);//how many links have been grabbed
for (var i = 0; i < links.length; i++) {
if (links[i].onmouseover !== null && links[i].onmouseover.toString().indexOf('function openit') > -1)
{
//toggling the funcitonality off
//remove it
links[i].setAttribute('target', '');
links[i].setAttribute('onmouseover', '');
}
else
{
//toggling the funcitonality on
//add it
links[i].setAttribute('target', 'blank');
links[i].setAttribute('onmouseover', 'function openit(elem){console.log(\'userScript will click on the link\');elem.click();};openit(this);');
}
}
}
}
);
As for popup blocking... I don't know.
I want to be able to use a ul list as an select form element, for styling reasons.
I'm able to populate an hidden input with my code (not included in this jsfiddle), and so far so good.But now I'm trying to let my ul behave like the select input when the keyboard is pressed, or the mouse is used.
In my previous question i had some problems with keyboard controls. They are now fixed. See: Autoscroll on keyboard arrow up/down
The problem that remains is that the mouse is not ignored when the keyboard buttons are pressed. This is causing the "hover effect" to listen to the keyboard input first, but than immediately going to the mouse and select this li item as being selected.
This can be seen in my jsfiddle example: http://jsfiddle.net/JVDXT/3/
My javascript code:
// scrollTo plugin
$.fn.scrollTo = function( target, options, callback ){
if(typeof options == 'function' && arguments.length == 2){ callback = options; options = target; }
var settings = $.extend({
scrollTarget : target,
offsetTop : 100,
duration : 0,
easing : 'linear'
}, options);
return this.each(function(){
var scrollPane = $(this);
var scrollTarget = (typeof settings.scrollTarget == "number") ? settings.scrollTarget : $(settings.scrollTarget);
var scrollY = (typeof scrollTarget == "number") ? scrollTarget : scrollTarget.offset().top + scrollPane.scrollTop() - parseInt(settings.offsetTop);
scrollPane.animate({scrollTop : scrollY }, parseInt(settings.duration), settings.easing, function(){
if (typeof callback == 'function') { callback.call(this); }
});
});
}
//My code
//The function that is listing the the mouse
jQuery(".btn-group .dropdown-menu li").mouseover(function() {
console.log('mousie')
jQuery(".btn-group .dropdown-menu li").removeClass('selected');
jQuery(this).addClass('selected');
})
//What to do when the keyboard is pressed
jQuery(".btn-group").keydown(function(e) {
if (e.keyCode == 38) { // up
console.log('keyup pressed');
var selected = jQuery('.selected');
jQuery(".btn-group .dropdown-menu li").removeClass('selected');
if (selected.prev().length == 0) {
selected.siblings().last().addClass('selected');
} else {
selected.prev().addClass('selected');
jQuery('.btn-group .dropdown-menu').scrollTo('.selected');
}
}
if (e.keyCode == 40) { // down
console.log('keydown');
var selected = jQuery('.selected');
jQuery(".btn-group .dropdown-menu li").removeClass('selected');
if (selected.next().length == 0) {
selected.siblings().first().addClass('selected');
} else {
selected.next().addClass('selected');
jQuery('.btn-group .dropdown-menu').scrollTo('.selected');
}
}
});
So could anyone teach me how to igonore the mouse when the keyboard buttons are pressed, but listing to the mouse when it's touched again by the user. Like the default select input form field.
Update
Here's a new jsfiddle.
Check this out:
http://jsfiddle.net/coma/9KvhL/25/
(function($, undefined) {
$.fn.dropdown = function() {
var widget = $(this);
var label = widget.find('span.valueOfButton');
var list = widget.children('ul');
var selected;
var highlighted;
var select = function(i) {
selected = $(i);
label.text(selected.text());
};
var highlight = function(i) {
highlighted = $(i);
highlighted
.addClass('selected')
.siblings('.selected')
.removeClass('selected');
};
var scroll = function(event) {
list.scrollTo('.selected');
};
var hover = function(event) {
highlight(this);
};
var rebind = function(event) {
bind();
};
var bind = function() {
list.on('mouseover', 'li', hover);
widget.off('mousemove', rebind);
};
var unbind = function() {
list.off('mouseover', 'li', hover);
widget.on('mousemove', rebind);
};
list.on('click', 'li', function(event) {
select(this);
});
widget.keydown(function(event) {
unbind();
switch(event.keyCode) {
case 38:
highlight((highlighted && highlighted.prev().length > 0) ? highlighted.prev() : list.children().last());
scroll();
break;
case 40:
highlight((highlighted && highlighted.next().length > 0) ? highlighted.next() : list.children().first());
scroll();
break;
case 13:
if(highlighted) {
select(highlighted);
}
break;
}
});
bind();
};
$.fn.scrollTo = function(target, options, callback) {
if(typeof options === 'function' && arguments.length === 2) {
callback = options;
options = target;
}
var settings = $.extend({
scrollTarget : target,
offsetTop : 185,
duration : 0,
easing : 'linear'
}, options);
return this.each(function(i) {
var scrollPane = $(this);
var scrollTarget = (typeof settings.scrollTarget === 'number') ? settings.scrollTarget : $(settings.scrollTarget);
var scrollY = (typeof scrollTarget === 'number') ? scrollTarget : scrollTarget.offset().top + scrollPane.scrollTop() - parseInt(settings.offsetTop, 10);
scrollPane.animate({scrollTop: scrollY}, parseInt(settings.duration, 10), settings.easing, function() {
if (typeof callback === 'function') {
callback.call(this);
}
});
});
};
})(jQuery);
$('div.btn-group').dropdown();
The key is to unbind the mouseover and rebind when mouse moves.
I refactored it a little by using a closure function, adding the logic to a jQuery method called dropdown so you can reuse it, using switch instead of a bunch of if's and more things.
Well, there are bazillions of plugins to transform a select to a list:
http://ivaynberg.github.io/select2/
http://harvesthq.github.io/chosen/
http://meetselva.github.io/combobox/
and I have mine too! (ready for touch devices using the same trick as http://uniformjs.com)
https://github.com/coma/jquery.select
But this question is about taking that HTML and make it behave like a select avoiding the hover issue right?
Here's a solution, I'm using mousemove as this will ensure that the right list item is selected as soon as the mouse starts moving again, with mouseover it only starts to select a list item upon entering a new list item:
Take the anonymous function and give it a name:
function mousemove() {
console.log('mousie')
jQuery(".btn-group .dropdown-menu li").removeClass('selected');
jQuery(this).addClass('selected');
}
Declare a global variable mousemoved indicating if the mouse has moved over the document and set it to false, on mousemove over the document, set it to true and attach the mousemove function to the mousemove event on the list items.
var mousemoved = false;
jQuery(document).mousemove(function() {
if(!mousemoved) {
$('.btn-group .dropdown-menu li').mousemove(mousemove);
mousemoved = true;
}
})
As soon as a key is pressed (at the start of the keydown event), use jQuery's .off() method to remove the mousemove event on the list items if it is present, and set mousemoved to false to ensure the mousemove event doesn't get attached again until the mouse is moved again.
jQuery(".btn-group").keydown(function(e) {
$('.btn-group .dropdown-menu li').off('mousemove');
mousemoved = false;
... // Some more of your code
Here's a jsFiddle.
I tried to solve your issue by prevent autoscroll, adding tabindex on the li, setting the focus on active, and using a flag to suppress mouse.
Fixed fiddle: http://jsfiddle.net/8nKJT/ [fixed an issue in Chrome ]
http://jsfiddle.net/RDSEt/
The issue is because of the automatic scroll which is triggered on keydown that again triggers mouseenter messes the selection of the li.
Note: The differences with the other approaches(answers here) I noticed is it scrolls on every keypress instead of scrolling only after reaching the top or bottom(normal behavior). You will feel the difference when you check the demo side-by-side.
Below is the list of change description and a small demo to explain how it was fixed,
Prevented auto scroll that is triggered on pressing up arrow/down arrow using e.preventDefault() http://jsfiddle.net/TRkAb/ [press up/down on the ul li], Now try the same on http://jsfiddle.net/TRkAb/1/ [No more scroll]
Added a flag on keydown to suppress the mouseevents on keydown, this flag is reset onmousemove
Added tabindex to li which would allow you to set focus using .focus function. [More info: https://stackoverflow.com/a/6809236/297641 ]
Calling .focus would automatically scroll to the desired location. (no need for scrollTo plugin) http://jsfiddle.net/39h3J/ - [Check how it scrolls to li that is on focus]
Check out the demo and code changes too (added few improvements) and let me know.
Also thanks to your question, I noticed this issue and bunch of other issue in one of the plugin I wrote.
I wrote a plugin few months back to filter options and also act exactly like a drop down.
DEMO: http://jsfiddle.net/nxmBQ/ [change filterType to '' to turnoff the filtering ]
The original plugin page is http://meetselva.github.io/combobox/
.. more
You could use a global to ignore the mouseover event if a keydown was pressed recently on the widget. For example:
var last_key_event = 0;
jQuery(".btn-group .dropdown-menu li").mouseover(function() {
if ((new Date).getTime() > last_key_event + 1000) {
console.log('mousie')
jQuery(".btn-group .dropdown-menu li").removeClass('selected');
jQuery(this).addClass('selected');
}
});
Then the keydown handler can set when it was handled to avoid interaction with the mouse:
//What to do when the keyboard is pressed
jQuery(".btn-group").keydown(function(e) {
last_key_event = (new Date).getTime();
...
});
May be it could make sense to have the last_key_event variable separate for each widget instead of being a global.
You could try this solution. It ignores the mousemove event if the coordinates have not changed (since the last mousemove event)
//The function that is listing the the mouse
var lastOffsets = "";
jQuery(".btn-group .dropdown-menu li").mouseover(function(e) {
var curOffsets = e.clientX+":"+e.clientY;
if(curOffsets == lastOffsets) {
// mouse did not really move
return false;
}
lastOffsets = curOffsets;
///// rest of your code
}
Updated fiddle to verify if this is what you were after:
http://jsfiddle.net/pdW75/1/
Approach A reasonable solution should imitate the behavior of other UI elements that serve a similar purpose. On all checked systems (Windows, Linux, major browsers), drop-down boxes behave as follows:
Mousing over an item highlights it. Pressing arrow keys change the selected element, and scroll accoringly. Moving the mouse selects the element underneath. If the selection is empty, pressing down selects the first element. Pressing up selects the last element.
Solution This code illustrates my approach to imitating the described behavior. It's kinda cool, try it...
Additional Considerations There would be a number of other options to suppress unwanted mouse movement to change the selected element. These include:
Keeping a state of last input method. If last selection was using the keyboard, hovering over an element will not select it, only clicking will
ignoring the mouseover event if the coordinates have not changed by a specified distance, e.g. 10 pixels
ignoring mouseover if the user has ever used the keyboard
However, at least for an application accessible to the public, it's always best to stick with established UI patterns.
The problem showing up is that when the mouse is left over a part of the expanded list, then selecting using the keys is nullified because the selection made by the keyboard immediately reverts to the item that happens to be under the mouse.
You can solve this problem and retain all functionality without doing any complicated conditional behavior or any removing of event handlers.
Just change your mouseover event handler to be a mousemove event handler. This way any keyboard navigation and selection is listened to and the mouse position is ignored anytime that the user is using the keyboard to select. And anytime the mouse is being used to select, then the mouse is listened to.
This sounds trivial but it seems to make your JS Fiddle behave perfectly and without any conflicting behavior between mouse and keyboard. Like this:
//The function that is listening to the mouse
jQuery(".btn-group .dropdown-menu li").mousemove...
(your code continues unchanged, only replacing mouseover with mousemove)
I have a single button in li with id "my_id". I attached two jQuery events with this element
1.
$("#my_id").click(function() {
alert('single click');
});
2.
$("#my_id").dblclick(function() {
alert('double click');
});
But every times it gives me the single click
Instead of utilizing more ad-hoc states and setTimeout, turns out there is a native property called detail that you can access from the event object!
element.onclick = event => {
if (event.detail === 1) {
// it was a single click
} else if (event.detail === 2) {
// it was a double click
}
};
Modern browsers and even IE-9 supports it :)
Source: https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail
The behavior of the dblclick event is explained at Quirksmode.
The order of events for a dblclick is:
mousedown
mouseup
click
mousedown
mouseup
click
dblclick
The one exception to this rule is (of course) Internet Explorer with their custom order of:
mousedown
mouseup
click
mouseup
dblclick
As you can see, listening to both events together on the same element will result in extra calls to your click handler.
You need to use a timeout to check if there is an another click after the first click.
Here is the trick:
// Author: Jacek Becela
// Source: http://gist.github.com/399624
// License: MIT
jQuery.fn.single_double_click = function(single_click_callback, double_click_callback, timeout) {
return this.each(function(){
var clicks = 0, self = this;
jQuery(this).click(function(event){
clicks++;
if (clicks == 1) {
setTimeout(function(){
if(clicks == 1) {
single_click_callback.call(self, event);
} else {
double_click_callback.call(self, event);
}
clicks = 0;
}, timeout || 300);
}
});
});
}
Usage:
$("button").single_double_click(function () {
alert("Try double-clicking me!")
}, function () {
alert("Double click detected, I'm hiding")
$(this).hide()
})
<button>Click Me!</button>
EDIT:
As stated below, prefer using the native dblclick event: http://www.quirksmode.org/dom/events/click.html
Or the one provided by jQuery: http://api.jquery.com/dblclick/
The modern correct answer is a mix between the accepted answer and #kyw 's solution.
You need a timeout to prevent that first single click and the event.detail check to prevent the second click.
const button = document.getElementById('button')
let timer
button.addEventListener('click', event => {
if (event.detail === 1) {
timer = setTimeout(() => {
console.log('click')
}, 200)
}
})
button.addEventListener('dblclick', event => {
clearTimeout(timer)
console.log('dblclick')
})
<button id="button">Click me</button>
A simple function. No jquery or other framework is required. Pass your functions as parameters
<div onclick="doubleclick(this, function(){alert('single')}, function(){alert('double')})">click me</div>
<script>
function doubleclick(el, onsingle, ondouble) {
if (el.getAttribute("data-dblclick") == null) {
el.setAttribute("data-dblclick", 1);
setTimeout(function () {
if (el.getAttribute("data-dblclick") == 1) {
onsingle();
}
el.removeAttribute("data-dblclick");
}, 300);
} else {
el.removeAttribute("data-dblclick");
ondouble();
}
}
</script>
I'm afraid that the behaviour is browser dependent:
It is inadvisable to bind handlers to
both the click and dblclick events for
the same element. The sequence of
events triggered varies from browser
to browser, with some receiving two
click events before the dblclick and
others only one. Double-click
sensitivity (maximum time between
clicks that is detected as a double
click) can vary by operating system
and browser, and is often
user-configurable.
http://api.jquery.com/dblclick/
Running your code in Firefox, the alert() in the click() handler prevents you from clicking a second time. If you remove such alert, you get both events.
Well in order to double click (click twice) you must first click once. The click() handler fires on your first click, and since the alert pops up, you don't have a chance to make the second click to fire the dblclick() handler.
Change your handlers to do something other than an alert() and you'll see the behaviour. (perhaps change the background color of the element):
$("#my_id").click(function() {
$(this).css('backgroundColor', 'red')
});
$("#my_id").dblclick(function() {
$(this).css('backgroundColor', 'green')
});
This answer is made obsolete through time, check #kyw's solution.
I created a solution inspired by the gist posted by #AdrienSchuler. Use this solution only when you want to bind a single click AND a double click to an element. Otherwise I recommend using the native click and dblclick listeners.
These are the differences:
Vanillajs, No dependencies
Don't wait on the setTimeout to handle the click or doubleclick handler
When double clicking it first fires the click handler, then the doubleclick handler
Javascript:
function makeDoubleClick(doubleClickCallback, singleClickCallback) {
var clicks = 0, timeout;
return function() {
clicks++;
if (clicks == 1) {
singleClickCallback && singleClickCallback.apply(this, arguments);
timeout = setTimeout(function() { clicks = 0; }, 400);
} else {
timeout && clearTimeout(timeout);
doubleClickCallback && doubleClickCallback.apply(this, arguments);
clicks = 0;
}
};
}
Usage:
var singleClick = function(){ console.log('single click') };
var doubleClick = function(){ console.log('double click') };
element.addEventListener('click', makeDoubleClick(doubleClick, singleClick));
Below is the usage in a jsfiddle, the jQuery button is the behavior of the accepted answer.
jsfiddle
Another simple Vanilla solution based on the A1rPun answer (see his fiddle for the jQuery solution, and both are in this one).
It seems that to NOT trigger a single-click handler when the user double-clicks, the single-click handler is necessarily triggered after a delay...
var single = function(e){console.log('single')},
double = function(e){console.log('double')};
var makeDoubleClick = function(e) {
var clicks = 0,
timeout;
return function (e) {
clicks++;
if (clicks == 1) {
timeout = setTimeout(function () {
single(e);
clicks = 0;
}, 250);
} else {
clearTimeout(timeout);
double(e);
clicks = 0;
}
};
}
document.getElementById('btnVanilla').addEventListener('click', makeDoubleClick(), false);
How to differentiate between single clicks and double clicks on one and the same element?
If you don't need to mix them, you can rely on click and dblclick and each will do the job just fine.
A problem arises when trying to mix them: a dblclick event will actually trigger a click event as well, so you need to determine whether a single click is a "stand-alone" single click, or part of a double click.
In addition: you shouldn't use both click and dblclick on one and the same element:
It is inadvisable to bind handlers to both the click and dblclick events for the same element. The sequence of events triggered varies from browser to browser, with some receiving two click events before the dblclick and others only one. Double-click sensitivity (maximum time between clicks that is detected as a double click) can vary by operating system and browser, and is often user-configurable.
Source: https://api.jquery.com/dblclick/
Now on to the good news:
You can use the event's detail property to detect the number of clicks related to the event. This makes double clicks inside of click fairly easy to detect.
The problem remains of detecting single clicks and whether or not they're part of a double click. For that, we're back to using a timer and setTimeout.
Wrapping it all together, with use of a data attribute (to avoid a global variable) and without the need to count clicks ourselves, we get:
HTML:
<div class="clickit" style="font-size: 200%; margin: 2em; padding: 0.25em; background: orange;">Double click me</div>
<div id="log" style="background: #efefef;"></div>
JavaScript:
<script>
var clickTimeoutID;
$( document ).ready(function() {
$( '.clickit' ).click( function( event ) {
if ( event.originalEvent.detail === 1 ) {
$( '#log' ).append( '(Event:) Single click event received.<br>' );
/** Is this a true single click or it it a single click that's part of a double click?
* The only way to find out is to wait it for either a specific amount of time or the `dblclick` event.
**/
clickTimeoutID = window.setTimeout(
function() {
$( '#log' ).append( 'USER BEHAVIOR: Single click detected.<br><br>' );
},
500 // how much time users have to perform the second click in a double click -- see accessibility note below.
);
} else if ( event.originalEvent.detail === 2 ) {
$( '#log' ).append( '(Event:) Double click event received.<br>' );
$( '#log' ).append( 'USER BEHAVIOR: Double click detected.<br>' );
window.clearTimeout( clickTimeoutID ); // it's a dblclick, so cancel the single click behavior.
} // triple, quadruple, etc. clicks are ignored.
});
});
</script>
Demo:
JSfiddle
Notes about accessibility and double click speeds:
As Wikipedia puts it "The maximum delay required for two consecutive clicks to be interpreted as a double-click is not standardized."
No way of detecting the system's double-click speed in the browser.
Seems the default is 500 ms and the range 100-900mms on Windows (source)
Think of people with disabilities who set, in their OS settings, the double click speed to its slowest.
If the system double click speed is slower than our default 500 ms above, both the single- and double-click behaviors will be triggered.
Either don't use rely on combined single and double click on one and the same item.
Or: add a setting in the options to have the ability to increase the value.
It took a while to find a satisfying solution, I hope this helps!
Here's an alternative of jeum's code for an arbitrary number of events:
var multiClickHandler = function (handlers, delay) {
var clicks = 0, timeout, delay = delay || 250;
return function (e) {
clicks++;
clearTimeout(timeout);
timeout = setTimeout(function () {
if(handlers[clicks]) handlers[clicks](e);
clicks = 0;
}, delay);
};
}
cy.on('click', 'node', multiClickHandler({
1: function(e){console.log('single clicked ', e.cyTarget.id())},
2: function(e){console.log('double clicked ', e.cyTarget.id())},
3: function(e){console.log('triple clicked ', e.cyTarget.id())},
4: function(e){console.log('quadro clicked ', e.cyTarget.id())},
// ...
}, 300));
Needed this for a cytoscape.js app.
Use the excellent jQuery Sparkle plugin. The plugin gives you the option to detect first and last click. You can use it to differentiate between click and dblclick by detecting if another click was followed by the first click.
Check it out at http://balupton.com/sandbox/jquery-sparkle/demo/
I wrote a simple jQuery plugin that lets you use a custom 'singleclick' event to differentiate a single-click from a double-click:
https://github.com/omriyariv/jquery-singleclick
$('#someDiv').on('singleclick', function(e) {
// The event will be fired with a small delay.
console.log('This is certainly a single-click');
}
I like to avoid jquery (and other 90-140k libs), and as noted browsers handle onclick first, so here is what I did on a website I created (this example also covers getting a clicked location local x y )
clicksNow-0; //global js, owell
function notify2(e, right) { // called from onclick= and oncontextmenu= (rc)
var x,y,xx,yy;
var ele = document.getElementById('wrap');
// offset fixed parent for local win x y
var xxx= ele.offsetLeft;
var yyy= ele.offsetTop;
//NScape
if (document.layers || document.getElementById&&!document.all) {
xx= e.pageX;
yy= e.pageY;
} else {
xx= e.clientX;
yy= e.clientY;
}
x=xx-xxx;
y=yy-yyy;
clicksNow++;
// 200 (2/10ths a sec) is about a low as i seem to be able to go
setTimeout( "processClick( " + right + " , " + x + " , " + y + ")", 200);
}
function processClick(right, x, y) {
if (clicksNow==0) return; // already processed as dblclick
if (clicksNow==2) alert('dbl');
clicksNow=0;
... handle, etc ...
}
hope that helps
Based on Adrien Schuler (thank you so much!!!) answer, for Datatables.net and for many uses, here is a modification:
Function
/**
* For handle click and single click in child's objects
* #param {any} selector Parents selector, like 'tr'
* #param {any} single_click_callback Callback for single click
* #param {any} double_click_callback Callback for dblclick
* #param {any} timeout Timeout, optional, 300 by default
*/
jQuery.fn.single_double_click = function (selector, single_click_callback, double_click_callback, timeout) {
return this.each(function () {
let clicks = 0;
jQuery(this).on('click', selector, function (event) {
let self = this;
clicks++;
if (clicks == 1) {
setTimeout(function () {
if (clicks == 1) {
single_click_callback.call(self, event);
} else {
double_click_callback.call(self, event);
}
clicks = 0;
}, timeout || 300);
}
});
});
}
Use
$("#MyTableId").single_double_click('tr',
function () { // Click
let row = MyTable.row(this);
let id = row.id();
let data = row.data();
console.log("Click in "+id+" "+data);
},
function () { // DBLClick
let row = MyTable.row(this);
let id = row.id();
let data = row.data();
console.log("DBLClick in "+id+" "+data);
}
);
let clickTimes = 0;
let timer = null;
roundBox.click = function (e) {
clearTimeout(timer);
timer = setTimeout(() => { // 单击事件
console.log("single click");
}, 600);
clickTimes++;
if (clickTimes == 2) { // 双击
clearTimeout(timer);
clickTimes = 0;
console.log("double click");
toggleExpanded(id);
}
}
this worked for me–
var clicked=0;
function chkBtnClcked(evnt) {
clicked++;
// wait to see if dblclick
if (clicked===1) {
setTimeout(function() {
clicked=0;
.
.
}, 300); // test for another click within 300ms
}
if (clicked===2) {
stopTimer=setInterval(function() {
clicked=0;
.
.
}, 30*1000); // refresh every 30 seconds
}
}
usage–
<div id="cloneimages" style="position: fixed;" onclick="chkBtnClcked(evnt)" title="Click for next pic; double-click for slide show"></div>
Just posting the native HTML answer just in case the need is to be easy and HTML.
<p ondblclick="myFunction()" id = 'id'>Double-click me</p>
This of course has native Jquery options. ie... $('#id').attr('ondblclick',function(){...}) or, as stated previously, $('#id').dblclick(function(){...});
I know this is old, but below is a JS only example of a basic loop counter with a single timer to determine a single vs double click. Hopefully this helps someone.
var count = 0;
var ele = document.getElementById("my_id");
ele.addEventListener('click', handleSingleDoubleClick, false);
function handleSingleDoubleClick()
{
if(!count) setTimeout(TimerFcn, 400); // 400 ms click delay
count += 1;
}
function TimerFcn()
{
if(count > 1) console.log('you double clicked!')
else console.log('you single clicked')
count = 0;
}
Try this code
let click = 0;
element.onclick = (event) => {
click++;
console.log(click);
setTimeout(() => {
click = 0;
}, 300);
if (click === 2) {
console.log("double Click");
click = 0;
console.log(click);
}
};
If you want to distinguish between a single and double click, the event handler of the single click has to wait until it is proven, that the single click is not the beginning of a double click. This makes single clicks lagging. The example shows this.
var distinguish = (() => {
var target = null;
var timeout = null;
return (element, action) => {
element.addEventListener ('click', e => {
if (e.target === target) {
clearTimeout (timeout);
target = null;
timeout = null;
action ('double');
} else {
target = e.target;
timeout = setTimeout (() => {
target = null;
timeout = null;
action ('single');
}, 500);
}
});
};
})();
var button = document.getElementById ('button');
distinguish (button, kind => console.log (kind + ' click'));
<input id="button" type="button" value="click">
Pure JS, to truly differentiate single- vs double-click, (e.g. not triggering both at the same time). I'm using this combination of the native event.detail and a custom delay, to prevent the single-click from firing, if it gets cancelled by a double-click.
This approach is also very performance friendly, as it doesn't start a new timer every time we click in quick succession.
The only minor thing (as with some of the other solutions too), is that it may still fire both events, if the user double-clicks very very slowly. This can be prevented by highering the delay, but that would make single-clicking feel even more laggy.
Also there is a lot of differences in the suggested answers as to how they handle quick multi-clicking. So to make things clear, here is what happens in every consecutive click with this approach:
triggers a slightly delayed single-click, if it isn't cancelled by a doubleclick
triggers double-click
nothing
triggers double-click
nothing
...(every 2nd click is a doubleclick, which feels very natural)
I included a snippet so you can test it for yourself.
document.querySelector('button').addEventListener('click', single_or_double);
let isSingleClick; // flag to allow or cancel single clicks
function single_or_double(){
if (isSingleClick = event.detail == 1){ //check for a singleclick and store flag globally at the same time
setTimeout(() => {
if(isSingleClick){ //check if the flag is still set after the delay
console.log("single");
}
}, 200); // singleclick delay in milliseconds
}
else if (event.detail == 2) {
console.log("double");
}
}
<button>Single OR Double-Click</button>