How to dismiss dropdown menu in WordPress template on new page - javascript

I'm working on a Wordpress template and one of the features is a dropdown menu in the header. You click the arrow to open it, and it remains open until you click the arrow to close it. But, when you click on one of the links, it still remains open on the next page. You have to click the arrow to close it.
I would like the dropdown menu to automatically close when navigating to a new page. Here is my js for the navigation... I'm following a tutorial from Lynda so I didn't write this code, but I haven't had enough experience with js to know which section of the code is doing what exactly.
Please let me know if you need any other information.
function initMainNavigation( container ) {
// Add dropdown toggle that display child menu items.
container.find( '.menu-item-has-children > a' ).after( '<button class="dropdown-toggle" aria-expanded="false">' + screenReaderText.expand + '</button>' );
// Toggle buttons and submenu items with active children menu items.
container.find( '.current-menu-ancestor > button' ).addClass( 'toggle-on' );
container.find( '.current-menu-ancestor > .sub-menu' ).addClass( 'toggled-on' );
container.find( '.dropdown-toggle' ).click( function( e ) {
var _this = $( this );
e.preventDefault();
_this.toggleClass( 'toggle-on' );
_this.next( '.children, .sub-menu' ).toggleClass( 'toggled-on' );
_this.attr( 'aria-expanded', _this.attr( 'aria-expanded' ) === 'false' ? 'true' : 'false' );
_this.html( _this.html() === screenReaderText.expand ? screenReaderText.collapse : screenReaderText.expand );
} );
}
initMainNavigation( $( '.main-navigation' ) );
// Re-initialize the main navigation when it is updated, persisting any existing submenu expanded states.
$( document ).on( 'customize-preview-menu-refreshed', function( e, params ) {
if ( 'primary' === params.wpNavMenuArgs.theme_location ) {
initMainNavigation( params.newContainer );
// Re-sync expanded states from oldContainer.
params.oldContainer.find( '.dropdown-toggle.toggle-on' ).each(function() {
var containerId = $( this ).parent().prop( 'id' );
$( params.newContainer ).find( '#' + containerId + ' > .dropdown-toggle' ).triggerHandler( 'click' );
});
}
});

I know that this question is almost a year old, but I wanted to go ahead and post an answer just in case someone needs it in the future.
The following lines from your code are what's causing the toggles to stay open when you go to a new page.
// Toggle buttons and submenu items with active children menu items.
container.find( '.current-menu-ancestor > button' ).addClass( 'toggle-on' );
container.find( '.current-menu-ancestor > .sub-menu' ).addClass( 'toggled-on' );
When you navigate to a page that is part of a sub-menu, these lines automatically add the 'toggle-on' class to the appropriate toggle button and parent sub-menu of that page. If you comment out those lines, the sub-menus will close when you navigate to a new page.

Related

I have a named function which works great on click. How can I run it on a specific element when the page loads?

So, I have a function called runFilter. It works great when I run it on click. If you look at the line underneath "on load, run the filter," that doesn't work at all. If it was a built-in function like .css() then it would work fine, but this isn't a built-in function and I've already failed at extending jQuery to make it one.
I'm probably doing something very obvious wrong here, but what I want to happen is for the function to fire once after the page is loaded, targeting this specific link: ul > li:first-child a.
jQuery(document).ready(function( $ ) {
function runFilter( event ) {
console.log( this );
event.preventDefault();
//* add active class on the active nav item
$( 'ul.attractions-filters a' ).removeClass( 'active' );
$( this ).addClass( 'active' );
//* add active class for visible things
term = $( this ).attr( 'data-term' );
$( '.type-attractions' ).removeClass( 'active' );
$( '.attractiontype-' + term ).addClass( 'active' );
}
// Show everything once the page is fully loaded
$( '.type-attractions' ).addClass( 'active' );
//* On load, run the filter
// $( 'ul.attractions-filters:first a' ).on( 'load', runFilter );
//* On click, run the filter
$( 'ul.attractions-filters a' ).on( 'click', runFilter );
});
While it's not clear which A of which UL you're actually trying to refer to, there are a bunch of different ways of doing it:
The example below depends on a few things:
jQuery will call any method attached through .on via the .click
method. It automatically binds it to the function.
jQuery will let you invoke known events through the .trigger method. It automatically binds it to the function
querySelector only returns the first element that matches a selector (may be easier to read than the equivalent jQuery selector)
let selector = 'ul.attractions-filters a';
let firstSelector = 'ul.attractions-filters:first a';
let firstChildSelector = 'ul.attractions-filters a:first';
let firstChildSelectorJQ = 'ul.attractions-filters:first a:first';
let whatYouAskedFor = 'ul > li:first-child a'
$(function() {
function runFilter() {
console.log(this)
}
$(selector).on('click', runFilter);
console.log( "This selector will click all A elements in the first UL with class 'attractions-filters'")
$(firstSelector).click();
$(firstSelector).trigger('click');
console.log( "This selector will click the first A element in every UL with class 'attractions-filters'")
$(whatYouAskedFor).click();
$(whatYouAskedFor).trigger('click');
console.log("These selectors will click the first A element in the first UL with class 'attractions-filters'")
$($(firstSelector)[0]).click();
$($(firstSelector)[0]).trigger('click');
$(firstChildSelector).click();
$(firstChildSelector).trigger('click');
runFilter.bind($(firstSelector)[0])();
console.log("These selectors will select only the first child of the first UL of class 'attractions-filters' and click it")
$(firstChildSelectorJQ).click();
$(firstChildSelectorJQ).trigger('click');
runFilter.bind($(firstChildSelectorJQ)[0])();
runFilter.bind(document.querySelector(selector))();
console.log("This selector is the requirement you gave")
runFilter.bind(document.querySelector(whatYouAskedFor))();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li>What You Asked For</li>
</ul>
<ul class="attractions-filters">
<li>UL 1, LI 1</li>
<li>UL 1, LI 2</li>
</ul>
<ul class="attractions-filters">
<li>UL 2, LI 1</li>
<li>UL 2, LI 2</li>
</ul>
You're very close!
Your code, modified below, with a few comments:
// altered to be a briefer document ready (Still no-conflict safe!)
jQuery(function( $ ) {
function runFilter( event ) {
event.preventDefault();
// add active class on the active nav item
$( 'ul.attractions-filters a' ).removeClass( 'active' );
$( this ).addClass( 'active' );
// add active class for visible things
term = $( this ).attr( 'data-term' );
$( '.type-attractions' ).removeClass( 'active' );
$( '.attractiontype-' + term ).addClass( 'active' );
}
// Show everything once the page is fully loaded
$( '.type-attractions' ).addClass( 'active' );
// On click, run the filter
$( 'ul.attractions-filters a' ).on( 'click', runFilter );
// NOTE: Choose ONE of the following three methods:
// Method #1: using trigger
$( 'ul.attractions-filters:first a' ).trigger( 'click' );
// Method #2: using click
$( 'ul.attractions-filters:first a' ).click();
// Method #3: better yet "chain" the methods to reduce duplicate code...
// NOTE: this replaces BOTH your .on('click') AND the .trigger or .click above...
$( 'ul.attractions-filters a' )
.on( 'click', runFilter )
.trigger( 'click');
});

I can't seem to get my dropdown code to function properly

I am trying to create a drop down menu that when the drop down button is clicked it shows the sub menu. When I click anywhere else though it should hide the sub menu.
Here is my code:
function initMainNavigation( container ) {
container.find( '.dropdown-toggle' ).click(function(e){
var dropdown = $( this );
e.preventDefault();
dropdown.next( '.children, .sub-menu' ).toggleClass( 'toggled-on' );
});
$("body").click(function(){
var dropdown = container.find( '.dropdown-toggle' );
dropdown.next( '.children, .sub-menu' ).removeClass('toggled-on');
});
}
initMainNavigation( $( '.main-navigation' ) );
But when I click the dropdown toggle the sub menu won't show. When I debugged it in firebug, the $("body").click() event is triggered as well. I am guessing it's because the '.main-navigation' is inside the "body".
I know that it works if I remove $("body").click(). However I can't click else where to hide the sub menu.
Your body click event bubbles to the .dropdown-toggle container so when you click .dropdown-toggle you trigger both events
function initMainNavigation( container ) {
container.find( '.dropdown-toggle' ).click(function(e){
var dropdown = $( this );
e.preventDefault();
dropdown.next( '.children, .sub-menu' ).toggleClass( 'toggled-on' );
});
$("body").click(function(e){
var dropdown = container.find( '.dropdown-toggle' );
if(!$(e.target).closest('.dropdown-toggle').length) {//trigger the toggle only if the element is not .dropdown-toggle or a child of it
dropdown.next( '.children, .sub-menu' ).removeClass('toggled-on');
}
});
}
initMainNavigation( $( '.main-navigation' ) );

Javascript - Hide a div with a reset button

I need a UL, containing the search results (ul.job_listings) to hide after a reset button is pressed.
So far a reset has been set up to reset the search form:
$( '.job_filters' ).on( 'click', '.reset', function () {
var target = $( this ).closest( 'div.job_listings' );
var form = $( this ).closest( 'form' );
form.find( ':input[name="search_keywords"], :input[name="search_location"], .job-manager-filter' ).not(':input[type="hidden"]').val( '' ).trigger( 'chosen:updated' );
form.find( ':input[name^="search_categories"]' ).not(':input[type="hidden"]').val( 0 ).trigger( 'chosen:updated' );
$( ':input[name="filter_job_type[]"]', form ).not(':input[type="hidden"]').attr( 'checked', 'checked' );
target.triggerHandler( 'reset' );
target.triggerHandler( 'update_results', [ 1, false ] );
job_manager_store_state( target, 1 );
return false;
} );
How would I add to it to also hide the results div?
Thanks for any help,
Liz.
Since you seem to be using jQuery, it you could just add
target.hide();
before the return statement.
edit - see comments above :-)

Slide toggle in toggleClass

I am trying to slide toggle my twenty-thirteen mobile menu with slide toggle and it only slide down but it comes back quickly (no slide). I injected other code to make it slide but it is buggy. Here's the original code
/**
* Enables menu toggle for small screens.
*/
( function() {
if ( ! nav || ! button ) {
return;
}
// Hide button if menu is missing or empty.
if ( ! menu || ! menu.children().length ) {
button.hide();
return;
}
button.on( 'click.twentythirteen', function() {
nav.toggleClass( 'toggled-on' );
if ( nav.hasClass( 'toggled-on' ) ) {
$( this ).attr( 'aria-expanded', 'true' );
menu.attr( 'aria-expanded', 'true' );
} else {
$( this ).attr( 'aria-expanded', 'false' );
menu.attr( 'aria-expanded', 'false' );
}
} );
and here is what i added
jQuery(document).ready(function () {
jQuery("button").on("click", function () {
jQuery( ".menu-primary-nav-container" ).slideToggle( "slow" );
});
});
Template link: https://twentythirteendemo.wordpress.com/
That template already has script assigned to click event and it toggles the class toggled-on on the menu list (and that is the reason you see no sliding). What you need to do is to disable new class this way:
.toggled-on .nav-menu, .toggled-on .nav-menu > ul {
display: none; /* It was block */
}

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

Categories