I'm trying to build the following for mobile browsers: I have a row of boxes. Each box holds additional information underneath and a href to another website. When I scroll the page via a certain box or just taphold it, i want to show the additional information. If I tap it, i want to go to the href.
I've built a solution with click, touchstart and touchend, which worked, but quite buggy, because click and touchstart are interfering (I guess). So I'm hoping to build a more solid version with hammer.js. My Idea of the event handling:
On touch start : The additional Information ist Shown.
If I release until 250ms: The Touch is counted as a tap and I'm sent to the href.
After 251ms: It's defenitely a taphold
On scrolling/touch move: It's defenitely a taphold
That's the js i have until now. I changed the starting point of the press time to 1ms and the threshold to 1000px to be able to scroll. pressup doesnt trigger if i press and scroll. I think pan is triggering instead? How can I change the settings of pressup?
var myElement = document.getElementById('myElement');
var mc = new Hammer(myElement);
mc.add(new Hammer.Press({
event: 'press',
pointer: 1,
threshold: 1000,
time: 1,
}));
mc.on('press', function(event) {
$('.skills').addClass( "show" );
});
mc.on('pressup', function(event) {
$('.skills').removeClass( "show" );
});
I've built a codepen (or where should i post it for mobile testing?)
http://codepen.io/Vin-ni/pen/JXYMXm
So I need two things to happen. Pressup needs to trigger and on Pressup i need to check if the time since press is more or less than 250ms.
it would be something like
mc.on('pressup', function(event) {
$('.skills').removeClass( "show" );
if (time since press < 251ms) {
window.location.href = (this).data(link);
}
});
Thanks a lot!!
My Solution (It binds the event to each div in a grid):
$('.class').each(function(){
var $this = $(this);
var mc = new Hammer.Manager(this);
mc.add( new Hammer.Tap() );
//customize Press event to trigger instantly + 1000px scrollable
mc.add(new Hammer.Press({
event: 'press',
pointer: 1,
threshold: 1000,
time: 1,
}));
mc.on('press tap', function(event) {
//do stuff
if (event.type == "tap") {
window.location.href = link;
$('.skills').removeClass( "show" );
}
});
mc.on('pressup', function(event) {
//undo stuff
});
});
Related
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)
I have a script that refreshes a Div on my website every 20 seconds. The problem is, once it refreshes, it scrolls to the to of the Div. I want it to stay at the last position and not scroll to the top after a refresh. Could someone please look at this script and maybe point out what I'm doing wrong? Thanks in advance!
var time = new Date().getTime();
var refreshTime = 20*1000;
$(document).bind("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error hover change", function(e) {
time = new Date().getTime();
});
var lastScrollPos = 0;
$('#feed1').on('scroll', function() {
lastScrollPos = this.scrollTop;
});
function refresh() {
if(new Date().getTime() - time >= refreshTime)
$('#feed1').load(location.href="/dashboard" , function () {
$(this).scrollTop(lastScrollPos);
});
else
setTimeout(refresh, refreshTime);
}
setTimeout(refresh, refreshTime);
Why don't you use feed1 div only for loading your dashboard contents and handle its position using style.
#feed1 {
height: 150px;
overflow: auto;
}
Add other data outside feed1 div because load method will overwrite feed1's content.
See this example if you are looking for something similar otherwise you can modify this example so that other can understand your requirement/scenario.
If you do location.href="/dashboard", the browser will discard all the page's state (including scripting variables) and load "/dashboard" (assigning a value to location.href is identical to calling location.assign("/dashboard")).
The jQuery load function will probably not even require you to reposition the scroll offset, if you gave it chance to execute!
Try:
$('#feed1').load("/dashboard #feed1");
UPDATE:
It seems the HTTP request fired by jQuery's load mechanism is receiving a truncated response in your case (content-length: 0).
You would have to put the scroll position you want to keep into localStorage. Try:
var time = new Date().getTime();
var refreshTime = 20*1000;
$(document).bind("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error hover change", function(e) {
time = new Date().getTime();
});
var previousScrollPos = localStorage.getItem("lastScrollPos");
if(previousScrollPos)
{
$('#feed1').scrollTop(previousScrollPos);
localStorage.removeItem("lastScrollPos");
}
function refresh() {
if(new Date().getTime() - time >= refreshTime)
{
localStorage.setItem("lastScrollPos", $('#feed1').scrollTop());
location.reload();
}
}
setInterval(refresh, refreshTime);
I'm not 100% sure that you want to bind to the scroll event of #feed1 or just of body, I haven't seen your page. If anybody clicks "load more" on the news feed, those additional items will be hidden again since you're reloading the page. Not ideal at all.
Many users will hate having the page periodically reload, it's also an accessibility failure since this will interfere with screen reading software. It might be a simpler idea to just put a refresh newsfeed icon on the page, which just reloads the whole page, when the user wants to (instead of periodically).
I am working with JavaScript and jQuery in an UIWevView on iOS.
I'v added some javascript event handler that allow me to capture a touch-and-hold event to show a message when someone taps an img for some time:
$(document).ready(function() {
var timeoutId = 0;
var messageAppeared = false;
$('img').on('touchstart', function(event) {
event.preventDefault();
timeoutId = setTimeout(function() {
/* Show message ... */
messageAppeared = true;
}, 1000);
}).on('touchend touchcancel', function(event) {
if (messageAppeared) {
event.preventDefault();
} else {
clearTimeout(timeoutId);
}
messageAppeared = false;
});
});
This works well to show the message. I added the two "event.preventDefault();" lines to stop imgs inside links to trigger the link.
The problem is: This also seems to prevent drag events to scroll the page from happen normally, so that the user wouldn't be able to scroll when his swipe happens to begin on an img.
How could I disable the default link action without interfering with scrolling?
You put me on the right track Stefan, having me think the other way around. For anyone still scratching their head over this, here's my solution.
I was trying to allow visitors to scroll through images horizontally, without breaking vertical scrolling. But I was executing custom functionality and waiting for a vertical scroll to happen. Instead, we should allow regular behavior first and wait for a specific gesture to happen like Stefan did.
For example:
$("img").on("touchstart", function(e) {
var touchStart = touchEnd = e.originalEvent.touches[0].pageX;
var touchExceeded = false;
$(this).on("touchmove", function(e) {
touchEnd = e.originalEvent.touches[0].pageX;
if(touchExceeded || touchStart - touchEnd > 50 || touchEnd - touchStart > 50) {
e.preventDefault();
touchExceeded = true;
// Execute your custom function.
}
});
$(this).on("touchend", function(e) {
$(this).off("touchmove touchend");
});
});
So basically we allow default behavior until the horizontal movement exceeds 50 pixels.
The touchExceeded variable makes sure our function still runs if we re-enter the initial < 50 pixel area.
(Note this is example code, e.originalEvent.touches[0].pageX is NOT cross browser compatible.)
Sometimes you have to ask a question on stack overflow to find the answer yourself. There is indeed a solution to my problem, and it's as follows:
$(document).ready(function() {
var timeoutId = 0;
$('img').on('touchstart', function(event) {
var imgElement = this;
timeoutId = setTimeout(function() {
$(imgElement).one('click', function(event) {
event.preventDefault();
});
/* Show message ... */
}, 1000);
}).on('touchend touchcancel', function(event) {
clearTimeout(timeoutId);
});
});
Explanation
No preventDefault() in the touch event handlers. This brings back scrolling behavior (of course).
Handle a normal click event once if the message appeared, and prevent it's default action.
You could look at a gesture library like hammer.js which covers all of the main gesture events across devices.
I'm trying to create a scrolling button that reacts differently to a quick click event than it does to a prolonged MouseDown (click and hold). The quick click event will scroll a specific number of pixels while click and hold will slowly scroll the pane until mouse up where it will stop.
This is what I have currently:
var mdown;
$('.next').bind('mousedown', function(event) {
mdown = event.timeStamp;
moving = setInterval(function(){
$('#main').scrollLeft($('#main').scrollLeft() + 5);
}, 1);
});
$('.next').bind('mouseup', function(event) {
clearInterval(moving);
if ((event.timeStamp - mdown) < 100)
$('#main').animate({ scrollLeft : '+=800'}, 500);
});
Is there another way of doing this without comparing event timestamps? Is a click event treated any differently than mousedown/mouseup? Thanks!
Check this plugin(It defines an event to handle long clicks):
https://github.com/pisi/Longclick
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();