In addition to MouseEvent
s I'd like to use a "long" TouchEvent
of a single finger/digit/input for my application (change mode, e.g. to start drawing or select elements to manipulate), while retaining all default actions like clicking/tapping, scrolling/swiping and hold-for-context-menu or hold-to-select.
In other words:
- a short touch (tap) should be analogous to a normal mouse click (usually emulated by browser)
- (short) touch and move (swipe) should cause normal scrolling
- a "longer" touch should be analogous to a mouse click-and-hold
- consequent move events should not cause scrolling but are handled by the application
- a long touch without move should cause normal secondary function (select, context-menu)
- pinch and other multi-touch gestures should use default handlers (for now)
There is no "hold-to-select" or similar event to my knowledge, so I am attempting to implement this myself.
Detecting a "long" touch before drag is quite simple (setTimeout()
, e.g. How to detect a long touch pressure with javascript for android and iphone?), however, the initial touchstart
already seems to trigger default event handlers, causing
- no scrolling (intended)
- Chrome on Windows
- Chrome on Android
- scrolling
- Safari on iOS (iPhone)
- Firefox on Windows and Android
- secondary functions
- select (not intended if move occurs)
- Safari on iOS (iPhone)
- magnifier (not intended if move occurs)
- Safari on iOS (iPhone)
- context-menu (intended, when no move occurs)
- Chrome on Windows: as intended (very long touch, no move)
- Firefox on Windows: as intended (very long touch, no move)
- Chrome on Android: none
- Firefox on Android: none
- select (not intended if move occurs)
on actual devices, despite preventDefault()
and stopPropagation()
calls from touchmove.
- is there a "better" way already (an event I don't know about)?
- is it possible to retroactively affect these envents/handlers (revert/undo events?)?
- is there a way to determine the default actions (select, context menu) and the respective timeout (browser / OS implementation dependant)?
or
- will I have to re-implement the very low-level handlers myself and then create and emit the necessary events (keeping different browser implementations in mind)?
Here's a preliminary snippet for testing (feel free to improve/extend):
let t = document.getElementById("t");
t.innerHTML += navigator.userAgent + '<br/>';
// timer
var timerid;
var touchduration = 500;
var longtouch = false;
function lt(e){
timerid = undefined;
longtouch = true;
e.preventDefault();
e.stopPropagation();
ls("LONG");
}
function ct(){if (timerid)window.clearTimeout(timer); timerid = undefined;}
function ls(s){
t.innerHTML += i + ' ' + s + '<br/>';
t.scrollTop = t.scrollHeight;
}
// log event
let i = 0;
let o;
function le(e){
if (e.type!=o){
ls( e.type + (longtouch?' LONG':'') );
o = e.type;
}
i++;
}
// mouse
t.addEventListener("mouseenter", e=>{le(e);});
t.addEventListener("mousedown", e=>{le(e);});
t.addEventListener("mouseup", e=>{le(e);});
t.addEventListener("mousemove", e=>{le(e);});
t.addEventListener("mouseout", e=>{le(e);});
t.addEventListener("mouseleave", e=>{le(e);});
t.addEventListener("click", e=>{le(e);});
t.addEventListener("dblclick", e=>{le(e);});
t.addEventListener("auxclick", e=>{le(e);});
// wheel
t.addEventListener("wheel", e=>{le(e);});
// touch
t.addEventListener("touchstart", e=>{le(e);
timerid = window.setTimeout(lt, 500, e);
});
t.addEventListener("touchend", e=>{le(e);
ct();
longtouch = false;
});
t.addEventListener("touchmove", e=>{le(e);
ct();
if (longtouch) {
e.preventDefault();
e.stopPropagation();
//e.stopImmediatePropagation();
}
});
t.addEventListener("touchcancel", e=>{le(e);});
t.addEventListener("drag", e=>{le(e);});
t.addEventListener("scroll", e=>{le(e);});
t.addEventListener("contextmenu", e=>{le(e);});
t.addEventListener("select", e=>{le(e);});
<div id="t" style="height:10em; max-height:100%; overflow-y:scroll; border: 1px solid green;"/>