I'm trying to detect the scroll event in Android browser (my specific version is 2.1, but U want it to work also on older versions). This seems impossible!
I first tried this:
document.addEventListener('scroll', function(){ alert('test'); }, false);
But nothing is triggered (except when the page load).
I thought: well, let's be crazy and emulate it by :
1. Detecting touchend
2. Polling the window.pageYOffset so we know when the window stops scrolling
3. Manually trigger a user function I want on scroll.
Unfortunately, the touchend event doesn't look to be triggered either... in fact, when we don't scroll and only tap the screen (touchstart + touchend), it works. As soon as we scroll the page in between (touchstart + touchmove + touchend), it breaks everything.
Now my most basic example only contains this:
document.addEventListener('touchend', function(){ alert('test'); }, false);
But the alert doesn't show up when we scroll with the finger and release the touch...
Does anyone has a suggestion?
Thanks.
You may want to crawl the source for JQuery Mobile, it supports android browsers and has scroll event listeners.
Or at least they say it does in the docs. :p
Here's the source
$.event.special.scrollstart = {
enabled: true,
setup: function() {
var thisObject = this,
$this = $( thisObject ),
scrolling,
timer;
function trigger( event, state ) {
scrolling = state;
var originalType = event.type;
event.type = scrolling ? "scrollstart" : "scrollstop";
$.event.handle.call( thisObject, event );
event.type = originalType;
}
// iPhone triggers scroll after a small delay; use touchmove instead
$this.bind( scrollEvent, function( event ) {
if ( !$.event.special.scrollstart.enabled ) {
return;
}
if ( !scrolling ) {
trigger( event, true );
}
clearTimeout( timer );
timer = setTimeout(function() {
trigger( event, false );
}, 50 );
});
}
};
Related
On my site, I am trying to fix the navigation so that when the browser is getting resized from desktop to mobile size, the mobile menu works. I have the mobile menu working on initial load, and the desktop navigation working on initial load, but when I run the script in a $(window).on('resize', function() {} and click an item as depicted in my script, the event fires always +1 each time the window was rested after a resize.
What I mean is, if I load the page, scale it into mobile size, click the menu and a dropdown item, the click event will fire once. Resize the window out and then back in, the click event will fire now 2 times, then 3, and so on, depending on how many times the browser was resized.
I'm not sure exactly what is going on in my resize script that is screwing everything up and I'm at my wits end at trying to figure it out. Normally people aren't sitting there resizing their browser from desktop to mobile, but my boss does when he show's clients a beta of their site and wants this to never be an issue.
Here is my resize script:
(function( $ ) {
var id,
$body = $('body'),
$window = $( window ),
$navSlider = $('.nav-slider'),
$navMask = $( '.nav-mask' ),
$navToggler = $( '.navbar-toggler' ),
$parent = $( '.menu-item-has-children' ),
$parentLink = $( '.dropdown-toggle' ),
$childContainer = $( '.dropdown-menu' );
$window.on( 'resize', function( e ) {
clearTimeout(id);
id = setTimeout(function() {
close();
var width = $window.width();
if ( width < 992 ) {
setHeightToNav();
$navMask.on( 'click', function() { close() } );
$navToggler.on( 'click', function() { open() } );
$parentLink.on( 'click', function( e ) {
e.preventDefault();
var $this = $( this );
$this.data( 'clicked', true );
console.log( $this.parent() );
} )
}
if ( width >= 992 ) {
resetNavHeight();
console.clear();
}
}, 500 );
} );
function setHeightToNav() {
if ( $body.hasClass( 'logged-in' ) ) {
var $wpAdminBar = $( '#wpadminbar' ).outerHeight();
$navSlider.css( { top: $wpAdminBar + 'px' } );
}
var $navHeight = $( '#header-container' ).outerHeight();
$navSlider.css( { marginTop: $navHeight + 'px' } );
}
function resetNavHeight() {
if ( $body.hasClass( 'logged-in' ) ) {
$navSlider.css( { top: 0 + 'px' } );
}
$navSlider.css( { marginTop: 0 + 'px' } );
}
function close() {
$body.removeClass( 'has-active-menu' );
setTimeout( function() {
$navSlider.removeClass( 'toggling' );
$parent.removeClass( 'show' );
$parentLink.attr( 'aria-expanded', false );
$childContainer.removeClass( 'show' ).removeAttr( 'style' );
$parentLink.data('clicked', false);
}, 250 );
console.log('close()');
}
function open() {
$body.addClass( 'has-active-menu' );
$navSlider.addClass( 'toggling' );
}
})( jQuery );
I've tried my script both with AND without the setTimeout function and it happens exactly the same.
On the project, we are using Bootstrap 4, with the Bootstraps Dropdown._clearMenus(); function commented out in the right places as it was causing conflicts with the functionality I wanted with the navigation.
A link to a site where you can see this is here. It's a WordPress site as well if that matters for anything.
Any help is appreciated. I've been at this for several hours and am at my wits end.
.on( 'click', function ) does not set the event listener, it adds an event listener. Try doing off('click') before setting it if you really need to set this listener here.
But note that any other 'click' listener for this element will also be removed.
That's for the quick fix. You could do better, but that would require more work (track with a boolean if you just changed "display mode", and add or remove the event listeners only then, for example).
For mobile devices there is not action like right-clicking - so I want to handle a long press for this.
I also need a normal "click" event.
For the long-press handling I found a solution, but when I add an onClick-listener, the onClick gets fired even if I only want the long-press event to be fired.
How can I prevent the Click Event when the longTap event fires?
Here is the Code + example:
var c = console.log.bind(console);
(function() {
$.fn.longTap = function(options) {
options = $.extend({
delay: 1000,
onRelease: null
}, options);
var eventType = {
mousedown: 'ontouchstart' in window ? 'touchstart' : 'mousedown',
mouseup: 'ontouchend' in window ? 'touchend' : 'mouseup'
};
return this.each(function() {
$(this).on(eventType.mousedown + '.longtap', function() {
$(this).data('touchstart', +new Date);
})
.on(eventType.mouseup + '.longtap', function(e) {
var now = +new Date,
than = $(this).data('touchstart');
now - than >= options.delay && options.onRelease && options.onRelease.call(this, e);
});
});
};
})(jQuery);
$('.long-tap').longTap({
delay: 1000, // really long tap
onRelease: function(e) {
c($(this).position(), e);
e.stopImmediatePropagation();
e.preventDefault();
alert('show context menu or something else:');
}
});
$('.long-tap').click(function(){
alert("click");
})
.test {
width: 200px;
height: 100px;
background-color: #DDD;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="test long-tap"></div>
You can use contextmenu for right click event:
$(document).on("contextmenu",function(e){
e.preventDefault();
// do the stuff
});
When you long press with the finger in your mobile device then the context menu will appear.
There is really no good way to do such thing, what you can do is test if longtap event is registered on event target for click event handler:
$('.long-tap').click(function(){
if ($(this).data('touchstart')) {
return;
}
...
});
In general, I think your general approach to implement context menu for touch screen devices should be reconsidered.
Best of luck!
So I have this code that whenever a page is onLoad, the user is not able to click any of the links unless it has finished loading the page in a specific region.
// note: this events are for the specific li tags of this.ui.liLink
'events' : {
'click #ui.catalogTab' : 'showCatalogsTabView',
'click #ui.transcriptTab' : 'showTranscriptsTabView',
'click #ui.facilitationTab' : 'showFacilitationTabView'
},
'ui' : {
'liLink' : '.catalog-menu > ul > li'
},
'enableTabClick' : function () {
this.ui.liLink.removeClass( 'disabled' );
this.ui.liLink.unbind( 'click.select' );
},
'disableTabClick' : function () {
this.ui.liLink.addClass( 'disabled' );
this.ui.liLink.bind( 'click.select', false );
}
this is working perfectly on desktop but when I use it on mobile devices, .bind() is not working and does not disable the event listener for click events. How do I do it on mobile?
So I finally solved my problem. In mobile, the event you have to listen for is touchstart. So I added it to my current code.
'enableTabClick' : function () {
this.ui.liLink.removeClass( 'disabled' );
this.ui.liLink.unbind( 'click.select touchstart' );
},
'disableTabClick' : function () {
this.ui.liLink.addClass( 'disabled' );
this.ui.liLink.bind( 'click.select touchstart', false );
},
It may be because in mobile devices there are not such events "click". Try mobile events - "tap" or "drag" for example. I think that problem in it.
I did a search in the site but didn't get useful info for my case. A simple demo can be found at jsfiddle. When I moved onto the div scroll bar and pressed the mouse, the event 'mousedown' was fired. And then I scrolled the bar, released the mouse. Unfortunately the event 'mouseup' was not fired in IE/Safari. Chrome and Firefox work fine. Is there a work-around solution for IE and Safari? Thanks!
Sample Code :
<div class="box">
<div class="box-inner">
</div>
</div>
<p id="text"></p>
jQuery :
$(document).ready(function() {
var $txt = $('#text');
$('.box').mouseup(function() {
$txt.text('mouseup');
});
$('.box').mousedown(function() {
$txt.text('mousedown');
});
});
Did more search in the site and got similar question. A solution proposed in the question is not prefect but worthy of trying.
$(document).ready(function() {
var $txt = $('#text'), $win = $(window), $doc = $(document);
$win.on('mousedown', function(event) {
$txt.text('mousedown');
if(event.pageX < ($win.width() - 10)) {
return;
}
$doc.on('mousemove', function(event) {
if(event.pageX < ($win.width() - 10)){
//mouse is off scrollbar
$(this).unbind(event);
$win.trigger('mouseup', ['manual fire']);
}
});
}).on('mouseup', function(event, str) {
$txt.text('mouseup: ' + str);
});
});
the mouseup fired for me in Safari... I can't test in IE as I'm on a Mac, but please try this:
http://jsfiddle.net/CmW9e/4/
$(document).ready(function() {
var $txt = $('#text');
$('.box').on("mousedown.box", function() {
$txt.text('mousedown');
$(document).one("mouseup.box", function() {
$txt.text('mouseup');
});
});
});
Basically binding the mouseup to the Document when you mousedownand then removing the bind after it's triggered :) this way the mouseup will always trigger no matter where the mouse is
I'm building a jquery mobile + phonegap app to bundle for iOS. The JQM site/app works as it should on a web browser. However, when bundled with phonegap and tested on a phone, it seems to forget javascript functions.
For example, I open/close panels on swipe. After a couple of swipes, ~10 opens/closes, it no longer responds to a swipe. I cannot open a panel. Other buttons are still functional, but I cant get the panel.
On a computer or webapp, I can do it all day long without it freezing up. Is there possibly something clearing functions from my javascript? Or should I define them in a different way?
$(document).on('pageinit', '#page', function() {
$(document).on("swipeleft swiperight", "#page", function(e) {
console.log('swiped!!')
});
});
Any ideas?
UPDATE:
Apparently it only "forgets" the function when I do it consistently back-and-forth for the ~10 tries. If I leave a ~2-3 second pause between each swipe, it seems to work fine for a lot longer. Maybe the new swipe events are occurring while the older swipe event is still completing the function??? And that is causing them to get tangled up and freeze? I've been kind of stuck on this. Any help/insight on memory management of phonegap app's javascript would be nice.
So, I found a fix.
$(document).on('pageinit', '#page', function() {
$(document).on("swipeleft swiperight", "#page", function(e) {
console.log('swiped!!')
});
});
This was the psuedo code I posted. It turns out, the console.log msg was getting called on every swipe, but the panel open/close calls that were omitted in the above code, were not.
Here's the complete old code:
$(document).on('pageinit','#page', function(){
$(document).on("swipeleft swiperight", "#page", function(e) {
console.log('swiped!!')
// We check if there is no open panel on the page because otherwise
// a swipe to close the left panel would also open the right panel (and v.v.).
// We do this by checking the data that the framework stores on the page element (panel: open).
if ($.mobile.activePage.jqmData( "panel" ) !== "open") {
if ( e.type === "swipeleft" ) {
$( "#right-panel" ).panel( "open" );
} else if ( e.type === "swiperight" ) {
$( "#left-panel" ).panel( "open" );
}
}
else if ($.mobile.activePage.jqmData( "panel" ) == "open"){
$( "#left-panel" ).panel( "close" );
$( "#right-panel" ).panel( "close" );
}
});
}
These changes fixed the code:
took the selector off the swipeleft swiperight function
$(document).on("swipeleft swiperight", "#page", function(e) {} became $(document).on("swipeleft swiperight", function(e) {}
and I added e.stopPropagation() on the event. I think it must've been JQM event propagation bubbling up the DOM and breaking everything.
$(document).on('pageinit', '#page', function() {
$(document).on("swipeleft swiperight", function(e) {
e.stopPropagation();
console.log('swiped!!')
// We check if there is no open panel on the page because otherwise
// a swipe to close the left panel would also open the right panel (and v.v.).
// We do this by checking the data that the framework stores on the page element (panel: open).
if ($.mobile.activePage.jqmData( "panel" ) !== "open") {
if ( e.type === "swipeleft" ) {
$( "#right-panel" ).panel( "open" );
} else if ( e.type === "swiperight" ) {
$( "#left-panel" ).panel( "open" );
}
}
else if ($.mobile.activePage.jqmData( "panel" ) == "open"){
$( "#left-panel" ).panel( "close" );
$( "#right-panel" ).panel( "close" );
}
});
}