Accordion Functionality - javascript

I've put together an accordion script that works quite nicely (haven't cross-browser tested) and allows for lots of content inside each drawer to be accessed and visible on screen. A lot of times accordions open and cause issues with positioning after opening. Anyway, the code I'm using has a toggle active function and a scroll function being called on click.
function toggleActive(link){ // Set anchor to active
if ( $(link).hasClass("active") ) {
$(link).removeClass("active");
} else {
$(link).addClass("active");
};
};
function scrollToElement(selector, time, verticalOffset) { // param 1 = id, param 2 = speed
time = typeof(time) != 'undefined' ? time : 1000;
verticalOffset = typeof(verticalOffset) != 'undefined' ? verticalOffset : 0;
element = $(selector);
offset = element.offset();
offsetTop = offset.top + verticalOffset;
$('html, body').animate({scrollTop: offsetTop }, time);
}
$('#accordion a').click(function(e) {
var link = '#' + event.target.id
$(".tab-content").slideUp();
$(".tab").removeClass("active");
toggleActive(link);
$(link).next().slideToggle("fast");
setTimeout(function() {
scrollToElement($(link), 500);
}, 500);
e.preventDefault();
});
So when clicked, all of the tabs are closed and made inactive, then the targeted "drawer" is opened and made active. If for any reason you click an already "active" drawer, it runs through the script again. What I'd like to do is place an IF statement that determines if what you just clicked is already open, and then simply close that drawer. Thanks in advance. I don't know why this is causing me headaches.
JSFiddle

As I understand you need another function as below:
function isAlreadyActive(link)
{
if ( $(link).hasClass("active") ) {
$(link).removeClass("active");
return true;
} else {
return false;
};
}
And you should call that function in your click event. This function will check if the link already active, if so just deactivates it and changes as you want.
$('#accordion a').click(function(e) {
var link = '#' + event.target.id
/* if it is already active, just deactivate it and exit*/
if(isAlreadyActive(link)){
return false;
}
$(".tab-content").slideUp();
$(".tab").removeClass("active");
toggleActive(link);
$(link).next().slideToggle("fast");
setTimeout(function() {
scrollToElement($(link), 500);
}, 500);
e.preventDefault();
});
I hope this helps.

Related

Scroll to previous div

based on this thread I added a scroll up to next div, like this:
var f = jQuery('.p');
var nxt = f;
jQuery(".next").click(function() {
if (nxt.next('.scroller').length > 0) {
nxt = nxt.next('.scroller');
} else {
nxt = f;
}
jQuery('html,body').animate({
scrollTop: nxt.offset().top
},
'slow');
});
var f = jQuery('.p');
var prev = f;
jQuery(".previous").click(function() {
if (prev.prev('.scroller').length > 0) {
prev = prev.prev('.scroller');
} else {
prev = f;
}
jQuery('html,body').animate({
scrollTop: prev.offset().top
},
'slow');
});
So this scrolls up and down very nicely.
The problem though, is that when the user scrolls, the script doesn't notice it. That is, the user scrolls from div1 to div4, when the user click on my "next"-button, he or she gets scrolled to div2. How can I solve this?
I checked into this but I cannot combine it with the above. There must be an easier way, right?
Any help much appreciated!
Oh... I think I might have solved it myself like this:
var jQuerycurrentElement = jQuery(".scroller").first();
jQuery(".next").click(function () {
var jQuerynextElement = jQuerycurrentElement.next(".scroller");
// Check if next element actually exists
if(jQuerynextElement.length) {
// If yes, update:
// 1. $currentElement
// 2. Scroll position
jQuerycurrentElement = jQuerynextElement;
jQuery('html, body').stop(true).animate({
scrollTop: jQuerynextElement.offset().top
}, 100);
}
return false;
});
jQuery(".previous").click(function () {
var jQueryprevElement = jQuerycurrentElement.prev(".scroller");
// Check if previous element actually exists
if(jQueryprevElement.length) {
// If yes, update:
// 1. $currentElement
// 2. Scroll position
jQuerycurrentElement = jQueryprevElement;
jQuery('html, body').stop(true).animate({
scrollTop: jQueryprevElement.offset().top
}, 100);
}
return false;
});
The above is based on this.
The only problem here is that when parts of a div is scrolled into view, the next and previous buttons sometimes behave strange. For example, when being between div2 and div3 and div 3 is most visible, the previous click can take the user back to div1, which feels not so logical. Can we adjust this somehow? I suppose I would have to do something with the offset but I am unsure.

do something when js element is loaded , is not working

I have this Jquery function to click on an element when its ready. its an interval doing it , the following function:
MonitorAndClick(selector) {
var ele = $(selector);
if (ele.length == 0) {
var intervalid = setInterval(function () {
var ele = $(selector);
if (ele.length > 0) {
ele[0].click();
clearInterval(intervalid);
return true;
}
}, 500);
} else {
ele[0].click();
return true;
}
}
the problem is in some cases , its not working. however this is an interval , and it's checking the element to be ready every 0.5 sec, so how can it be possible ? is there any other way to check the element is ready ?
additional note:
I have an accordion. I have a function to open the accordion->open one of the items->open the tab page in detail section
this is the function :
//--reach to this point, open accordion index 2--------
ShowAccordion(2);
//----open the item with specific Id in accordion items------
setTimeout(function () {
var selector = "tr[gacategory = '/myprotection/mywills/item_" + parseInt(willId) + "]";
MonitorAndClick(selector);
}, 500);
the point is this element SHOULD be there , sometimes its not loading fast enough , and I WANT TO HAVE A WAY TO CHECK IF ITS LOADED, THEN CLICK ON THAT.
Updated code after comments
var selector = "tr[gacategory = '/myprotection/mywills/item_" + parseInt(willId) + "]";
$("#selector").ready(function () {
console.log('**********.... selector is loaded ....*****');
if (!$("#selector").hasClass('selected'))
MonitorAndClick(selector);
});
still not working.
Why do you want to rely on 0.5 seconds delay to make sure your element is present in DOM. You should be invoking this function only after your element is present in the DOM. If there is another condition that drives when this element is added to the DOM, then call this function once that condition is achieved.
You may want to try https://api.jquery.com/ready/
It seems like jquery ready function can be applied on individual elements too

collapsing section and scrolling back to top

I am working on a long one-pager. Yes, I know, we hate one-pagers. At least I promise not to implement any parallax-effect, I promise :)
I have multiple sections I can open/close. This part works fine.
The problem: those sections get pretty long, and when they are being closed/collapsed, the user find himself somewhere in the middle of the one-pager.
So, when collapsing a section, I want it to collapse AND to smooth scroll back to the top/the start of the collapsed section.
Here my script:
// Section-Collapse
//---------------------------------------------------------
$("section a.read-more").click(function() {
if($(this).parents("section").hasClass("expanded")) {
var scrollAnchor = $(this).attr("data-scroll"),
scrollPoint = $(".anchor[data-anchor='" + scrollAnchor + "']").offset().top - 0;
$("body,html").animate({
scrollTop: scrollPoint
}, 1500, function() {
// close/collapse section
$(this).parents("section").addClass("close");
$("section.expanded.close div.expandable-content").slideUp();
$(this).parents("section").removeClass("expanded").removeClass("close");
alert("this test-message is being displayed");
});
} else {
// open section
$(this).parents("section").addClass("expanded");
$("section.expanded div.expandable-content").slideDown();
}
});
The problem: this part is not being executed EXCEPT the alert message, that one works. Although it is trying to open the dialog window multiple times and Firefox offers me to block this behavior.
// einklappen
$(this).parents("section").addClass("close");
$("section.expanded.close div.expandable-content").slideUp();
$(this).parents("section").removeClass("expanded").removeClass("close");
alert("this test-message is being displayed");
It scrolls back to top, to the anchor, but the section will not collapse...
Any ideas why it won't collapse?
Regards,
Milan
---------------------------UPDATE
So, it was a problem with the scope of variable "this".
This code here seems to work fine:
// Section-Collapse
//---------------------------------------------------------
$("section a.read-more").click(function() {
if($(this).parents("section").hasClass("expanded")) {
var scrollAnchor = $(this).attr("data-scroll"),
scrollPoint = $(".anchor[data-anchor='" + scrollAnchor + "']").offset().top - 0;
var global_this = $(this);
$("body,html").animate({
scrollTop: scrollPoint
}, 1500, function() {
// einklappen
global_this.parents("section").addClass("close");
$("section.expanded.close div.expandable-content").slideUp();
global_this.parents("section").removeClass("expanded").removeClass("close");
alert("this test-message is being displayed");
});
// return false;
} else {
// ausklappen
$(this).parents("section").addClass("expanded");
$("section.expanded div.expandable-content").slideDown();
}
});
What is bothering me: why this script tries to open multiple alert dialogs?

JavaScript won't work when in the same file as other JavaScript code, and only when 'defer' is included. Why?

I have a piece of JQuery code that animates an inline link to scroll smoothly to a <section> with an assigned ID on the same page (below).
/*Smooth Scrolling effect*/
$('a[href*="#"]:not([href="#"])').click(function() {
if (location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname) {
var target = $(this.hash);
target = target.length ? target : $('[name=' + this.hash.slice(1) + ']');
if (target.length) {
$('html, body').animate({
scrollTop: target.offset().top
}, 1000);
return false;
}
}
});
For some reason, this will only work when it is placed externally of the rest of my JavaScript code
//*Side Navigation Menu*//
/* Open Side Nav - Set the width of the side navigation to 250px when burger menu icon is clicked. This perhaps needs rehashing a whole bunch more to make it more my own*/
function openNav() {
document.getElementById("mySidenav").style.width = "300px";
}
/*Close Side Nav - Set the width of the side navigation to 0 when close button is clicked*/
function closeNav() {
document.getElementById("mySidenav").style.width = "0";
}
//*Email Popup Form - Currently resets user's view to the top of the screen. This needs to be fixed.*//
$ = function(id) {
return document.getElementById("popup");
}
var show = function(id) {
$(id).style.display = 'block';
}
var hide = function(id) {
$(id).style.display = 'none';
}
//*On hover over images on homescreen, display a black opacity box - Needs transferring to a seperate 'homepage' specific JavaScript file*//
$(function() {
$('#img0').hover(function() {
$('#fadeBox0').fadeIn(500);
}, function() {
$('#fadeBox0').fadeOut();
});
});
$(function() {
$('#img1').hover(function() {
$('#fadeBox1').fadeIn(500);
}, function() {
$('#fadeBox1').fadeOut();
});
});
$(function() {
$('#img2').hover(function() {
$('#fadeBox2').fadeIn(500);
}, function() {
$('#fadeBox2').fadeOut();
});
});
$(function() {
$('#img3').hover(function() {
$('#fadeBox3').fadeIn(500);
}, function() {
$('#fadeBox3').fadeOut();
});
});
I think the comments adequately (to my knowledge, I'm a beginner) explain what the JavaScript is supposed to do, but for some reason, some of this has stopped working as well. I don't know what I could have possibly changed, or where, as the rest of the website relies purely on HTML and CSS. (Note:After just testing something out, it appears that ALL of the above JavaScript has stopped working except for the small section labelled 'Side Navigation Menu'). Any help as to why this is happening would be much appreciated.
Thank you in advance!
Edit: I neglected to mention, the Smooth Scrolling Effect works when in an external JavaScript file, but only when Defer is used in the script tag. I've yet to try this with my other segments of JavaScript, but I don't want my code fragmented into individual JavaScript files for each individual function.
OK, more than "what is broken" let's try to wrap your head around the code.
This says: (what happens in processing)
Get all elements that do not have an href attribute equal to "#" (ALL elements, really?)
THEN get all the a elements that have an href attribute with "#" in them in that set
$('a[href*="#"]:not([href="#"])').click(function() {
This says: (what happens in processing)
get all the "a" elements that have an href with # in them
THEN exclude those that do not have an href attribute equal to "#"
$('a[href*="#"]').not('[href="#"]').on('click', function(){
Thus that second form is more efficient:
$('a[href*="#"]').not('[href="#"]').on('click', function() {
if (location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname) {
var target = $(this.hash);
target = target.length ? target : $('[name=' + this.hash.slice(1) + ']');
if (target.length) {
$('html, body').animate({
scrollTop: target.offset().top
}, 1000);
return false;
}
}
});
that $('html, body') - would $('body') work there? Why animate those/both?
$(someselector).click(function(){ is shortcut for $(someselector).on('click',function()( so just use the second form.
//Email Popup Form - Currently resets user's view to the top of the
screen. This needs to be fixed.//
In isolation this does nothing (DID overwrite jQuery alias $ before
// do NOT replace the alias:
var popme = function(id) {
return document.getElementById("popup");
};
These are broken:
var show = function(id) {
$(id).style.display = 'block';
};
var hide = function(id) {
$(id).style.display = 'none';
};
Fixed versions:
var show = function(id) {
$(id)[0].style.display = 'block';
};
var hide = function(id) {
$(id)[0].style.display = 'none';
};
show("#myid");
hide("#myid");
Why this and not just use jQuery since you have it already?
$("#myid").show();
$("#myid").hide();
//*On hover over images on homescreen, display a black opacity box - Needs transferring
ONE document ready event handler:
$(function() {
$('#img0').hover(function() {
$('#fadeBox0').fadeIn(500);
}, function() {
$('#fadeBox0').fadeOut();
});
$('#img1').hover(function() {
$('#fadeBox1').fadeIn(500);
}, function() {
$('#fadeBox1').fadeOut();
});
$('#img2').hover(function() {
$('#fadeBox2').fadeIn(500);
}, function() {
$('#fadeBox2').fadeOut();
});
$('#img3').hover(function() {
$('#fadeBox3').fadeIn(500);
}, function() {
$('#fadeBox3').fadeOut();
});
});
Alternate with classes (assumes the fadeBox class in on a child element)...
$('#img0,#img1,#img2').hover(function() {
$(this).find('.fadeBox').fadeIn(500);
}, function() {
$('.fadeBox').fadeOut();
});
Alternate 2, use classes on whatever those point to:
$('.myImages').hover(function() {
$(this).find('.fadeBox').fadeIn(500);
}, function() {
$('.fadeBox').fadeOut();
});
Note hover like this is short for mouseenter and mouseout event handlers. ref: https://api.jquery.com/hover/

need to modify this jquery pop menu script to work with ajax

I am using this script from: http://pop.seaofclouds.com/
The problem is if you call the script multiple times it causes a cascading effect of a pop-out within a pop-out for as many times as you call the script.
I'm trying to figure out how to prevent it from executing when the popout has already been set. Here's the script:
//
// pop! for jQuery
// v0.2 requires jQuery v1.2 or later
//
// Licensed under the MIT:
// http://www.opensource.org/licenses/mit-license.php
//
// Copyright 2007,2008 SEAOFCLOUDS [http://seaofclouds.com]
//
(function($) {
$.pop = function(options){
// inject html wrapper
function initpops (){
$(".pop").each(function() {
var pop_classes = $(this).attr("class");
if ( $(this).find('.pop_menu').length) {
// do nothing
} else {
$(this).addClass("pop_menu");
$(this).wrap("<div class='"+pop_classes+"'></div>");
$(".pop_menu").attr("class", "pop_menu");
$(this).before(" \
<div class='pop_toggle'></div> \
");
}
});
}
initpops();
// assign reverse z-indexes to each pop
var totalpops = $(".pop").length + 100;
$(".pop").each(function(i) {
var popzindex = totalpops - i;
$(this).css({ zIndex: popzindex });
});
// close pops if user clicks outside of pop
activePop = null;
function closeInactivePop() {
$(".pop").each(function (i) {
if ($(this).hasClass('active') && i!=activePop) {
$(this).removeClass('active');
}
});
return false;
}
$(".pop").mouseover(function() { activePop = $(".pop").index(this); });
$(".pop").mouseout(function() { activePop = null; });
$("body").on("click", ".pop", function(){
closeInactivePop();
});
// toggle that pop
$("body").on("click", ".pop_toggle", function(){
$(this).parent(".pop").toggleClass("active");
});
}
})(jQuery);
now when i load this script on an ajax call the new pop-out menus work but the old ones do not react to the onclick event.
You shouldn't mess with the plugin. It works exactly like it should.
Better show us how you call this on elements that you already have.
Also I don't like this plugin. Better use something from JqueryUI
You can do such thing in much easier way.
[edit]
I tried your first code (the plugin) and it works correctly for me.
[edit]
OK. I get it. You call $.pop(); multiple times. You shouldn't! Calling $.pop(); will pin up the drop down menu to all elements that has class="pop". This is the reason why you have such funny stack.
Just use $.pop(); once.
Plugin doesn't give ability to connect NEW elements that was dynamically created on the page.
Removed pop from ajax call and just called this on success:
$(".pop").each(function() {
var pop_classes = $(this).attr("class");
if ( $(this).find('.pop_menu').length) {
// do nothing
} else {
$(this).addClass("pop_menu");
$(this).wrap("<div class='"+pop_classes+"'></div>");
$(".pop_menu").attr("class", "pop_menu");
$(this).before(" \
<div class='pop_toggle'></div> \
");
}
});
// assign reverse z-indexes to each pop
var totalpops = $(".pop").length + 100;
$(".pop").each(function(i) {
var popzindex = totalpops - i;
$(this).css({ zIndex: popzindex });
});
// close pops if user clicks outside of pop
activePop = null;
function closeInactivePop() {
$(".pop").each(function (i) {
if ($(this).hasClass('active') && i!=activePop) {
$(this).removeClass('active');
}
});
return false;
}
$(".pop").mouseover(function() { activePop = $(".pop").index(this); });
$(".pop").mouseout(function() { activePop = null; });

Categories