Modernizr.mq not working in Safari & multiple event triggers? - javascript

I've got a sub navigation that has 3 different styles and functions based on browser width. See it live here.
$(function() {
$(window).resize(function() {
if(Modernizr.mq('(min-width:641px) and (max-width: 1200px)')) {
$(".subnav-menu").click(function() {
$('.primary-subnav').slideToggle();
$('.subnav-close').show();
});
$(".subnav-close").click(function() {
$('.primary-subnav').slideToggle();
$('.subnav-close').hide();
});
$(".tablet-subnav li").click(function() {
$('.primary-subnav').slideToggle();
$('.subnav-close').hide();
});
}
else if(Modernizr.mq('(max-width: 640px)')) {
$(".subnav").click(function() {
$('.primary-subnav').slideToggle();
$('.subnav-mobile-open').toggle();
$('.subnav-mobile-close').toggle();
});
}
}).trigger('resize');
});
The menu that should be showing up on click is not showing up at all on Safari on my desktop or phone, tested on several other macs and got nothing. It's working fine in Chrome/Firefox other than sometimes it will fire the menu's slideToggle multiple times. What am I doing wrong?
Edit:: The menu appears to not expand in mobile safari or mobile chrome at all, whereas I thought this was purely a safari issue. The little arrow on mobile and the menu button tablet do change though, and if I tap under there were the menu should be, it reacts as if going to the link, but the menu is not visible... Really strange.

Try using .off( "click", "**" ) on the click event handlers that were added from one media query and replace them with the .on( "click" ) event handlers that you need for the current media query.
Also, you can create a nice fade effect without the common problem of multiple queued animations by adding .stop( true, true ) to the chain.
Without your html, I couldn't really test it, but here's about what it should look like:
$( window ).on( "resize", function ()
{
if( Modernizr.mq( "(min-width:641px) and (max-width: 1200px)" ))
{
$( ".subnav" ).off( "click", "**" );
$( ".subnav-menu" ).on( "click", function ()
{
$( ".primary-subnav" )
.stop( true, true)
.slideToggle();
$( ".subnav-close" )
.stop( true, true )
.show();
});
$( ".subnav-close, .tablet-subnav li" ).on(" click", function ()
{
$( ".primary-subnav" )
.stop( true, true )
.slideToggle();
$( ".subnav-close" )
.stop( true, true )
.hide();
});
}
else if ( Modernizr.mq( "(max-width: 640px)" ))
{
$( ".subnav-menu, .subnav-close, .tablet-subnav li" ).off( "click", "**" );
$( ".subnav" ).on( "click", function ()
{
$( ".primary-subnav" )
.stop( true, true )
.slideToggle();
$( ".subnav-mobile-open, .subnav-mobile-close" )
.stop(true, true)
.toggle();
});
}
})
.resize();

Related

Scroll page to element on mobile is not working but on desktop yes, preventDefault is a problem?

I'm doing a website for desktop and mobile as well, the menu works perfect on desktop but not working on mobile, because I want the smothly scroll to id I use this code:
I found out that event.preventDefault() block a function I turn it off and it transfers me to id, but the animation is disabled at this point
$( 'a[href^="#"]' ).on( 'click', function ( event ) {
var target = $( $( this ).attr( 'href' ) );
var znacznik = $( $( this ).attr( 'a' ) );
if ( target.length ) {
event.preventDefault();
$( 'html, body' ).animate( {
scrollTop: target.offset().top - 80
}, 1000 );
}
} );
Is there any way to make it works on android? Maybe another function then event.preventDefault(); ?
I believe you may be overthinking this one, put an href on the button you want to scroll to, like so:
<button></button>
And for the smooth scrolling all I would do is set your CSS to the following:
html {
scroll-behavior: smooth;
}
Sets the entire page to have animations be smooth between elements.

Resize function events fire 2 times more each time the window was resized

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).

jquery slidetoggle how to set if mouse click other, close slidetoggle

I using jquery slidetoggle to show a DIV
but I need set if mouse click not in div.list go close this slideToggle
$( "#list_button" ).click(function() {
$( ".list" ).slideToggle( "fast" );
});
I only found if mouseout.... I cant find how to set if click any "anywhere on the page" to close this toggle
for testing : http://jsfiddle.net/sdgwbyv8/
$( "body" ).click(function( event ) {
if(
event.target.className!='list' && event.target.parentNode.parentNode.className!="list"
) {
$( ".list" ).slideToggle('fast');
}
});
Demo: http://jsfiddle.net/sdgwbyv8/9/ One possible solution, i guess there are better ones....
You can do it by event.stopPropagation():
$("#list_button").click(function (event) {
if ($(".list").is(":hidden")) {
event.stopPropagation();
$(".list").slideToggle("fast");
}
});
$('body').click(function () {
$(".list").hide();
});
$(".list").click(function (event) {
event.stopPropagation();
});
Working Fiddle

Make the collapsible sortable accordion sort in collapse shape

I have accordion is collapsible and sortable.
Look here full code in action http://jsfiddle.net/wvtPw/
And this the JS code I'm using
$( "#accordion" )
.accordion({
header: "> div > h3",
collapsible: true
})
.sortable({
handle: "h3",
placeholder: "ui-state-highlight",
stop: function( event, ui ) {
// IE doesn't register the blur when sorting
// so trigger focusout handlers to remove .ui-state-focus
ui.item.children( "h3" ).triggerHandler( "focusout" );
}
});
The only problem when I'm trying to sort the expanded div group is big and hard to sort and when its the first div and you drag it, you can't see below it because if the height size
See this image below is example of collapsed div, see how easy to use and you can see below it easily.
So what I need to reach is when the user trying to sort expanded div, the flying div turn into collapsed shape like this
And when he drop the element just turn back to expanded like normal
I recommend doing the following:
$(function() {
var active = false,
sorting = false;
$( "#accordion" )
.accordion({
header: "> div > h3",
collapsible: true,
activate: function( event, ui){
//this fixes any problems with sorting if panel was open
//remove to see what I am talking about
if(sorting)
$(this).sortable("refresh");
}
})
.sortable({
handle: "h3",
placeholder: "ui-state-highlight",
start: function( event, ui ){
//change bool to true
sorting=true;
//find what tab is open, false if none
active = $(this).accordion( "option", "active" );
//possibly change animation here (to make the animation instant if you like)
$(this).accordion( "option", "animate", { easing: 'swing', duration: 0 } );
//close tab
$(this).accordion({ active:false });
},
stop: function( event, ui ) {
ui.item.children( "h3" ).triggerHandler( "focusout" );
//possibly change animation here; { } is default value
$(this).accordion( "option", "animate", { } );
//open previously active panel
$(this).accordion( "option", "active", active );
//change bool to false
sorting=false;
}
});
});
DEMO:
http://jsfiddle.net/m939m/2/
Please let me know if you have any questions! Cheers!
have a look at the documentation for sortable
look at the sortable event start( event, ui ). The logic would then check to see if the item is expanded. if so then close it. after sort expand it again
http://api.jqueryui.com/sortable/#event-start
Add the code below before the stop event on your sortable object.
over: function(event, ui) {
$('#accordion').accordion({active:false});
},
http://jsfiddle.net/wvtPw/8/
While this code works for the collapsing/expanding issue when sorting, the "activate"-function causes an issue regarding opening the first item in the accordion. Opening and closing the first item makes it impossible to reopen. Continuing with the next item, same thing happens. In the end the complete list of items will not be possible to expand.
Since this is more of a UX question, my suggestion is to offer a different UX. I would disable sorting by default and offer a button to toggle sorting on/off. When sorting is enabled, collapse all the fields and disable the accordion.
$( '.accordion-toggle' ).on('click', function() {
$( "#accordion" ).toggleClass( 'sorting' );
});
$( "#accordion:not(.sorting)" )
.accordion({
header: "> div > h3",
collapsible: true
});
$( "#accordion.sorting" )
.sortable({
handle: "h3",
placeholder: "ui-state-highlight",
stop: function( event, ui ) {
// IE doesn't register the blur when sorting
// so trigger focusout handlers to remove .ui-state-focus
ui.item.children( "h3" ).triggerHandler( "focusout" );
}
});
EDIT: (2018-06-18)
I missed that this is jQuery UI. You probably want to use the enable/ disable features.
$( '.accordion-toggle' ).on( 'click', function() {
if ( $( '#accordion' ).hasClass( 'sorting' ) ) {
$( '#accordion' ).removeClass( 'sorting' )
.accordion( "enable" )
.sortable( "disable" );
} else {
$( '#accordion' ).addClass( 'sorting' )
.sortable( "enable" )
.accordion( "disable" )

Memory management in javascript jquery mobile with phonegap

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" );
}
});
}

Categories