Keep menu from closing when using touch events - javascript

I have hooked up a simple long touch function that after 500ms uses the "open" API command to open the context menu. The menu opens. However, on "touchend" the menu disappears. It only stays if I touchmove over the context menu before "touchend". Is there a way to prevent this sort of behaviour? From the source code, only a "touchstart" in a different part of the dom should trigger a close event.
Code is below, in case useful. Not that a delegate of tr is required by my context menu - to explain the targetTr variable use below.
var mobDevice_onLongTouch,
mobDevice_touchTimer,
mobDevice_longPressDuration = 500; //length of time we want the user to touch before we do something
//handle long press on the datatable
var touchArea = document.querySelector("#table");
touchArea.addEventListener("touchstart", touchAreaTouchStart, false);
touchArea.addEventListener("touchend", touchAreaTouchEnd, false);
function touchAreaTouchStart(e) {
var targetTr = $(e.target).closest('tr');
mobDevice_touchTimer = setTimeout(function () { touchArea_onLongTouch(targetTr) }, mobDevice_longPressDuration)
};
function touchAreaTouchEnd(e) {
if (mobDevice_touchTimer) {
clearTimeout(mobDevice_touchTimer) //reset the clock
}
};
function touchArea_onLongTouch(target) {
$('#table').contextmenu('open', target);
};

I solved this. ContextMenu was working fine, but the DOM control I was touching on registered a change event (to highlight a table row) on touchend. So the context menu popped up during touch and hold, then got cleared by a DOM change at touchend.
The solution was to manually add the highlight table row event to touchstart and preventDefault on touchend (when the touch target was inside the table)

Related

Javascript - Which event to listen to know if a popup menu comes up

I want to capture events in Javascript like link click, input type, button hit/submit etc and send it to an application (recording user actions). Later I will play those user events and do automation testing.
I have a specific case, that I do not know how to capture the user event. When I bring mouse cursor over menu region, a pop up menu shows up. Let's take an example. In dev.lmtools.com site, bring mouse cursor to "Test Environment" tab. You will see smething like image below. In that image, you can see the highlighted menu link "Calculate Endpoints" that user will click.
My job is to record user event when popup menu shows up and as well when user clicks link "Calculate Endpoints". I have explored mouseover, mouseexit, mouseenter, mouseleave event handlers without success. Mouseover generates so many events, so this I want to exclude. Mouseenter fires at page start, when it goes to menu area event does not fire.
I am interseted to know which event I should listen for, what is the unique identifier of element that pops up, identifier of link thats clicked by user, so that I can play afterwards accordingly.
Any help in this regard highly appreciated.
You can try Intersection Observer
The Intersection Observer API provides a way to asynchronously observe
changes in the intersection of a target element with an ancestor
element or with a top-level document's
For example, you can add a IDto the popup container and then, ( Note - I did not ran this code. May have some syntax errors )
// definition
function popupObserver(el, cb) {
let opt = {
root: document.documentElement
}
let observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
cb(entry.intersectionRatio > 0);
});
}, opt);
observer.observe(el);
}
then you use above function like,
popupObserver(document.querySelector("#popup_container_id"), trackPopup);
function trackPopup(isVisible){
let linkEl = null;
if(linkEl) {
linkEl.removeEventListener("click", trackMouseClick)
}
if(isVisible) {
// User hover over the link. capture popup. below code is a dummy code
tracker.track(EVENT.POPUP_HOVER);
linkEl = document.querySelector("#link_id");
linkEl.addEventListener("click", trackMouseClick)
}
}
function trackMouseClick() {
// dummy code to track link click
tracker.track(EVENT.LINK_CLICKED)
}

Kendo UI Chart disable legend item right click event

I have an application that uses a Kendo UI Chart with a legend. When the user clicks on a legend item, the Kendo onLegendItemClick(e) method gets called. However the event that gets passed to this function does not contain the originalEvent, so there is no way to distinguish between right and left clicks.
Here is the relevant API reference: https://docs.telerik.com/kendo-ui/api/javascript/dataviz/ui/chart/events/legenditemclick
I tried adding an event listener and capturing the 'mousedown' event before onLegendItemClick is invoked as shown below. However, this approach will fail on touch screen devices (iPads, tablets, mobile devices, etc).
document.addEventListener("mousedown", saveMouseDown, true);
function saveMouseDown(ev) {
$scope.mouseDownEvent = ev;
}
$scope.$on("$destroy", function () {
document.removeEventListener(saveMouseDown);
});
The application has a separate directive for handling right clicks. Is there a way to prevent Kendo from calling the onLegendItemClick(e) method when a user right clicks the legend item?
Add "click" to the list of saved events1:
document.addEventListener("mousedown click", saveEvent, true);
function saveEvent(ev) {
$scope.savedEvent = ev;
}
$scope.$on("$destroy", function () {
document.removeEventListener(saveEvent);
});
Related question: How to prevent right click from deselecting marker in Kendo-UI

Regaining focus in iFrame with jQuery context menu

I've created a fiddle to reproduce the problem.
https://jsfiddle.net/rvwp47Lz/23/
callback: function (key, option) {
console.log("You clicked the test button", this);
// Need the iframe contents to regain focus so the mouse events get caught
setTimeout(function () {
$iframe[0].contentWindow.focus();
}, 100);
}
Basically, what I want to happen is the mouse move events to be caught after closing the context menu.
I can call focus on the iFrame's body or document but it doesn't seem to have any effect.
After you right click one of the items within the iframe and select an item, the mousemove event on the iframes body is no longer called (you can also notice that the hover CSS effect on the items are no longer working).
Ideas?
After some debugging and playing around with jQuery.contextMenu's code it seems the issue actually comes from the itemClick function. I added comments to the code and will add an issue to their github for a possible fix (unless there's some reason they're disabling default here)
// contextMenu item click
itemClick: function (e) {
var $this = $(this),
data = $this.data(),
opt = data.contextMenu,
root = data.contextMenuRoot,
key = data.contextMenuKey,
callback;
// abort if the key is unknown or disabled or is a menu
if (!opt.items[key] || $this.is('.' + root.classNames.disabled + ', .context-menu-submenu, .context-menu-separator, .' + root.classNames.notSelectable)) {
return;
}
// This line is causing the issue since it's preventing the default actions which puts
// mouse events back into place. Chrome must disable mouse move events when the contextmenu event
// gets triggered to improve performance.
//e.preventDefault();
e.stopImmediatePropagation();

JQuery Mobile "tap" event on button also triggers "tap" on element behind it

I have a JQuery Mobile page in which the content is a list in which the user can tap to select (highlight) elements. After a desired number of list elements are selected, they can be deleted by tapping the Delete button in the footer. The page works fine on my desktop, but in a mobile environment (iPhone & iPad), pressing the delete button also triggers a tap event for the list element underneath the button.
This picture shows how my page normally looks. If the user taps the delete button, the selected element is deleted but the element underneath the delete button will be highlighted.
Why is this happening and what can I do to fix it?
EDIT (some code):
Here is the event mapper:
$(document).delegate("#delete-button", "tap", deleteButtonTapped);
Here is the function:
var deleteButtonTapped = function(event, data) {
event.stopPropagation();
var possessedNotes = [];
$('.ui-btn-up-e').each(function(){
$(this).slideUp();
var id = $(this).attr("id").split(" "); //id is loanId + " " + docId
possessedNotes.push(notesList[[id[1], id[2]]]);
});
// console.log(possessedNotes);
$.post("srv/move_notes_into_possession.php", { possessedNotes: possessedNotes }, function(response) {
console.log(response);
}, "json");
$("#footer").slideUp();
};
I'm maintaining an old app that uses this feature, and I'm seeing the exact same issue happening.
I was able to prevent underlying elements from also being 'tapped' using the event method, preventDefault.
$('#cancelButton').on('tap', function(event) {
event.preventDefault();
// event-handler code
});
Events on DOM elements propagate or "bubble". You need to use jQuery's event.stopPropagation() function in the event handler to stop the event from traveling to the parent elements.
http://api.jquery.com/event.stopPropagation/

Display DIV only if user has been Idle for X amount of time

I would like to display a helpful DIV that basically shows the user how to accomplish something on a particular page, but only if the user has been idle for a period of time, say, 30seconds.
What I mean by "Idle" is:
Not clicking any links
Not right clicking anywhere
Exceptions:
I would like to exclude the following conditions from the Is User Idle rule:
User has scrolled up or down/left or right
User has pressed mouse button on an empty area on the site/ or on an element which has no source/link for example, an image with no hyperlink.
and, Pressing keyboard buttons
Can this be done? Or can we only detect when a particullar event occurs?
Any thoughts/suggestions/resources will be greatly appreciated.
Thank you
fairly basic...
var trigger = 30000
$.(function(){
setInterval('displayInf()',trigger );
$('body').bind('click dblclick keypress mousemove scroll', function(){
clearDisplayInf();
});
});
function displayInf()
{
$('body').append('<div>Your notification div</div>');
}
function clearDisplayInf()
{
trigger = clearInterval(trigger);
trigger = setInterval('displayInf()', 30000 );
}
that should do the trick - you could add some script to make the div removable and start the timer again once its removed but that just polishing up really..
Event in DOM would bubble from leaf to root, thus add a event listener on document would make sense.
But since we are possibiliy stop bubbling for click event in certain element, register click event on document may not work perfectly, in that case, register mousedown and mouseup event would help:
var timer; // create a timer at first
// restart timer on click
function startIdle() {
timer = setTimeout(function() { /* show div */ }, time);
}
if (document.addEventListener) {
document.addEventListener('mouseup', startIdle, false);
}
else {
document.attachEvent('onmouseup', startIdle);
}
// start the first timer
startIdle();

Categories

Resources