javascript - Expand Collapse functionality breaks jQuery -
in project i'm using vertical-accordion-menu-plugin-for-jquery-nav-accordion allows me make parent links clickable. have made minor changes jquery make keyboard accessible. looks besides 1 little thing. when expand levels , close parent's container, sub-level items not longer showing expand/collapse button. reasons breaks. https://jsfiddle.net/webira7/mvtf6zve/
/* nav accordion plugin v1.1.2 ************************************/ (function($){ $.fn.navaccordion = function(options, callback){ this.each(function(){ //options var settings = $.extend({ expandbuttontext : "+", //text inside of expand button collapsebuttontext: "-", //text inside of collapse button selectedexpand: "true", //expand selected channel selectedclass: "selected", //class used detect selected channel - check "parentelement" class (the parent <li> default) multiplelevels: "true", //apply accordion levels - setting false apply accordion first level buttonwidth: "20%", //width of accordion expand/collapse button percentage or pixels buttonposition: "right", //position of button - 'right' default - can choose 'left' slidespeed: "fast", //speed of slide animation - "fast", "slow", or number in milliseconds such 500 parentelement: "li", //parent element type, class or id - don't need change if you're using ul > li > ul pattern childelement: "ul", //child element type, class or id - don't need change if you're using ul > li > ul pattern headersonly: false, //false default - setting true make link sub-nav behave if set header only, making link inaccessible - option useful if using plugin non-navigation area headersonlycheck: false, // false default - set true apply accordion links set "header only" (have no href) delaylink: false, //delay following href of links until after accordion has expanded delayamount: null //time in milliseconds delay before following href - use "slidespeed" default if nothing else set }, options); var container = this, //multiple levels variable multi = settings.multiplelevels ? '': ' > ' + settings.childelement + ' > '; //add class container $(container) .addclass('accordion-nav'); //apply has-subnav class lis uls - add accordion buttons styles $(multi + settings.parentelement, container).each(function(){ if ( ($(this).contents(settings.childelement).length > 0 && settings.headersonlycheck == false) || (!($('> a', this).attr('href')) && settings.headersonlycheck == true) ) { //apply class , styles parent item $(this).addclass('has-subnav') .css('position', 'relative') .find('>a') .css('margin-' + settings.buttonposition, settings.buttonwidth); //add expand button elements $(' > ' + settings.childelement, this) .before('<span class="accordion-btn-wrap"><a href="#"><span class="accordion-btn accordion-collapsed">' + settings.expandbuttontext + '</span><a href="#"><span class="accordion-btn accordion-expanded">' + settings.collapsebuttontext + '</span></a></span></a>'); //apply styles expand button $('.accordion-btn-wrap', this) .css({ 'width': settings.buttonwidth, 'position': 'absolute', 'top': 0, 'text-align': 'center', 'cursor': 'pointer', 'display': 'inline-block' }) .css(settings.buttonposition, 0); $('.accordion-btn ', this) .css({ 'display': 'inline-block', 'width': '100%' }); $('.accordion-expanded', this) .css('display', 'none'); } //apply styles <a> tags set header if (!($('> a', this).attr('href')) || settings.headersonly){ $(this) .addclass('accordion-header-only') .find('.accordion-btn-wrap') .css({ 'width': '100%', 'text-align': settings.buttonposition }) .find('.accordion-btn ') .css({ 'width': settings.buttonwidth, 'text-align': 'center' }); } //delay link mode if (settings.delaylink && !settings.headersonly) { var currentthis = this, speed = settings.delayamount != null ? settings.delayamount : settings.slidespeed; if (speed == "fast") { speed = 200; } else if (speed == "slow") { speed = 600; } $('> a', currentthis).on('click',function(e){ if (!$('> .accordion-btn-wrap', currentthis).hasclass("accordion-active")) { e.preventdefault(); var href = $(this).attr('href'); clicktoggle($('> .accordion-btn-wrap', currentthis)); //go link after delay settimeout(function(){ window.location = href; }, speed) } }) } }); var selectednavaccordion = $(settings.parentelement + '.' + settings.selectedclass + ' > .accordion-btn-wrap', container); //debounced button height event listener var buttonheightresize = debounce(function(){ //run button height buttonheight(); //expand selected channel expandselected(); }, 250); $(window).on('resize', buttonheightresize); //set button heights buttonheight(); //expand selected channel expandselected(); //on click function $(container).on('click', '.accordion-btn-wrap', function(e) { e.preventdefault(); clicktoggle(this); }); //callback if (typeof callback == "function") { callback(); } /* functions *******************************/ //click toggle function function clicktoggle(element) { var nextchild = $(element).next(settings.childelement), currentexpandbtn = $('.accordion-expanded', element), currentcollapsebtn = $('.accordion-collapsed', element), parentobj = $(element).closest(settings.parentelement); if (nextchild.is(':visible')) { nextchild .slideup(settings.slidespeed); $(element) .removeclass('accordion-active'); currentexpandbtn .css('display', 'none'); currentcollapsebtn .css('display', 'inline-block'); parentobj.add(parentobj.siblings('.active')).add(parentobj.find('.active')).removeclass('active'); } else { $(element).closest(settings.childelement).find('.accordion-active') .removeclass('accordion-active') .next(settings.childelement) .slideup(settings.slidespeed).prev() .find('.accordion-expanded') .css('display', 'none') .parent().find('.accordion-collapsed') .css('display', 'inline-block'); parentobj.add(parentobj.siblings('.active')).add(parentobj.find('.active')).removeclass('active'); $(element) .addclass('accordion-active'); nextchild .slidetoggle(settings.slidespeed); currentexpandbtn .css('display', 'inline-block'); currentcollapsebtn .css('display', 'none'); parentobj.addclass('active'); } } //expand selected channel function function expandselected(){ if(settings.selectedexpand){ if(!settings.headersonlycheck){ selectednavaccordion.find('.accordion-expanded') .css('display', 'inline-block'); selectednavaccordion.find('.accordion-collapsed') .css('display', 'none'); selectednavaccordion.addclass('accordion-active') .next(settings.childelement) .css('display', 'block'); selectednavaccordion.closest(settings.parentelement) .addclass('active'); } else { $(settings.parentelement + '.' + settings.selectedclass + ' > ' + settings.childelement, container) .css('display', 'block'); $(settings.parentelement + '.' + settings.selectedclass).addclass('active'); } } } //accordion button height function function buttonheight(){ $('.accordion-btn', container).each(function(){ //show uls heights calculated correctly $(settings.parentelement + '.has-subnav > ' + settings.childelement, container) .css('display', 'block'); //calculate , set heights var parentitem = $(this).closest(settings.parentelement), lineheight = $('> a', parentitem).innerheight(); $(this) .css({'line-height': lineheight + 'px', 'height': lineheight}); //hide uls under lis , reset expand/collapse buttons $(settings.parentelement + ((settings.headersonlycheck) ? ' ' : '.has-subnav > ') + settings.childelement, container) .css('display', 'none'); $('.accordion-expanded') .css('display', 'none'); $('.accordion-collapsed') .css('display', 'inline-block'); }) } //debounce function function debounce(func, wait, immediate) { var timeout; return function() { var context = this, args = arguments; var later = function() { timeout = null; if (!immediate) func.apply(context, args); }; var callnow = immediate && !timeout; cleartimeout(timeout); timeout = settimeout(later, wait); if (callnow) func.apply(context, args); }; }; }); } })(jquery);
the error related line below not finding '.accordion-collapsed' element, due searching parent(), whic assumes specific dom structure. using .closest() more flexible. 1 way fix replace
.parent().find('.accordion-collapsed').css('display', 'inline-block');
with
.closest('ul').find('.accordion-collapsed').css('display', 'inline-block');
line taken section:
$(element).closest(settings.childelement).find('.accordion-active') .removeclass('accordion-active') .next(settings.childelement) .slideup(settings.slidespeed).prev() .find('.accordion-expanded') .css('display', 'none') .parent().find('.accordion-collapsed') .css('display', 'inline-block');
Comments
Post a Comment