I have an accordion that works really well, it looks good on the site and works as it should. However, I'm trying to add some more JavaScript functionality to it, to make it more it look more professional.
i want to make first accordion tab open by using JavaScript. thanks in advance.
HTML Code
<div class="accordion"><b>Heading 1</b></div>
<div class="panel">
<p class="text-light">Text 1</p>
</div>
<div class="accordion"><b>Heading 2</b></div>
<div class="panel">
<p class="text-light">Text 2</p>
</div>
JS Code
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].onclick = function() {
var active = document.querySelector(".accordion.active");
if (active && active != this) {
active.classList.remove("active");
active.nextElementSibling.classList.remove("show");
}
this.classList.toggle("active");
this.nextElementSibling.classList.toggle("show");
}
}
I think Jquery UI's accordion has the first tab open by default and never allows you to have all tabs closed at once.
Check your .js file to see if it's being overridden by active: false. If active: false is there either delete it or change it to active: 0; (0 is first tab (zero based indexing))
Active: false will require the setting collapsible: true, which allows for closing a tab by clicking it so you may also see that in there.
Related
I'm trying to make a menu (with buttons) that open links.
when you hover on the buttons, a slideDown reveals more information on that link.
I've gotten all those features to technically work, however i can't get the animation speed to go any slower than instantly.
I'm really new to javascript and Jquery, and it took me 2-3 days to get the javascript and CSS to do what i have so far... and yeah it's probably bloated... but i'm still proud i got this done so far :D
PS, I know most menus are made w/ul's but I really like the way the buttons look and detested trying to put the list together. last time i tried used a seperate ul for the information and it kept styling the second list like the first because it was inside it... so annoying. I also tried vertical-link list w/CSS but still think flat 'buttons' are so boring. i really like the 3D esk of the actual html
HTML:
<div class="mainmenu">
<div id="homemenu">
<button id="home" class="mmbutton active">Home</button>
<div id="homesub" class="sub active">-just a bit about this page</div>
</div>
<div id="photosmenu">
<button id="photos" class="mmbutton">Photos</button>
<div id="photossub" class="sub inactive">-just a bit about this page
</div>
</div>
</div>
javascript/jquery:
$(function(){
var mmbutton = $('.mmbutton');
var start = "http://";
var address = "[my web address"; //add "http:
var about = "[web address]/aboutme.html";
var id = 0;
var rel = 0;
var mmsub = 0;
//<click link buttons:
$(mmbutton).click(function(){
var id = $(this).attr('id');
if (id === "home") {
location.replace(start+address);
}else if (id === "about") {
window.alert("I'm sorry I don't have this page set up yet. Thank you for visiting my page!");
//add additional buttons here under 'else if' unless its a subdomain
}else {
location.replace(start+id+'.'+address);//goes to any subdomain by id
}});
//>detect hover
$(mmbutton).hover(function(){
id = $(this).attr('id');
rel = '#'+id+'sub';
mmsub = '#'+id+'menu';
console.log('mouseenter'+rel);
$(rel).removeClass('inactive');
$(rel).stop().slideDown(500000);
}, function(){
console.log('mouseleave'+rel);
$(rel).addClass('inactive');
if ( $(this).hasClass('active')) {
$(rel).removeClass('inactive');
console.log('this is active');
}if ($(rel).hasClass('inactive')){
$(rel).stop().slideUp(500000);
}});});
relevante CSS:
.inactive {
display: none;
}
.sub {
transition-duration: 1s;
}
You can do it setting all that info divs to display:none and use slideToggle() function for that. Considering you want to keep the subdiv's opened when you're over them, one option is create a span element that include the button and the subdiv, and apply the hover to that span. So...
HTML:
<div class="mainmenu">
<div id="homemenu">
<span class="subcontainer">
<button id="home" class="mmbutton active">Home</button>
<div id="homesub" class="sub">-just a bit about this page</div>
</span>
</div>
<div id="photosmenu">
<span class="subcontainer">
<button id="photos" class="mmbutton">Photos</button>
<div id="photossub" class="sub">-just a bit about this page</div>
</span>
</div>
</div>
CSS:
.sub {
display: none;
/*transition-duration: 1s; IMPORTANT: REMOVE THIS!!*/
}
JQUERY:
$('span.subcontainer').hover(function() {
$(this).find('div.sub').slideToggle('slow');
});
IMPORTANT: Check that to make it work you have to remove the transition style you've created for .sub divs (it interfeers with the jquery function).
NOTE: I don't use the div.homemenu or div.photosmenu as the containers for the hover because div's normally have some styles pre-applied by default and can interfeer with the desired behaviour (for example, they normally have width=100% so the hover applies even when you're outside of the button or subdiv in the same line). span is normally more innocuous to use it just as a wrapper.
I hope it helps
Oh! i got it. i was trying to do too much (show off.../ using what im learning).
I removed the line that added and removed the class 'inactive' and just toggled the SlideUp and slideDown when i wanted it too. now i can adjust the animation speed:
(HTML remains unchanged)
CSS: removed the "transition-duration: 1s;"
JavaScript:
$(function(){
var mmbutton = $('.mmbutton');//any/all buttons
var activebut= 0; //detect button classes
var mmdiv = $("div[id$='menu']");//detect button sub info
var start = "http://";
var address = "[address]/index.html"; //add "http://" + [blog or games] + address
var about = "http://[address]/aboutme.html";
var id = 0;
var sub = 0;
var slidespeed= 450; //slideUP/slideDown animation speed //added var for speed
//<click link buttons: (unchanged)
$(mmbutton).click(function(){
id = $(this).attr('id');
if (id === "home") {
location.replace(start+address);
}else if (id === "about") {
location.replace(start+'[address]/aboutme/index.html')
//add additional buttons here under 'else if' unless its a subdomain
}else {
location.replace(start+id+'.'+address);//goes to any subdomain by id
}
});
//<hover display:
//<detect mouse ON button
$(mmbutton).hover(function(){
id = $(this).attr('id');
sub = '#'+id+'sub';
activebut= $(this);
if ( $(activebut).hasClass('active')) {
}else {
$(sub).stop().slideDown(slidespeed);
}
});
//<detect mouse off button AND div
$(mmdiv).mouseleave(function(){
if ( $(activebut).hasClass('active')) {
}else {
$(sub).stop().slideUp(slidespeed);
}
});
});
I have a pretty complex page where I have a number of instances of CodeMirror in hidden tabs within tabs. To then make it even more complex I remember the last active tabs.
I've manage to get it half working (http://codepen.io/anon/pen/LheaF) the problems are with the Second Editor tabs:
Its loading the Second tabs before the main Code Mirror tabs has been clicked. When you do click the Code Mirror tab it doesn't load the editor correctly either, until you click twice.
I want the second tabs to call the refresh() method if its already been initiated, like I do for the main editor.
Bug where its duplicating the secondary editors
(function($) {
var mainEditor;
function initMainCodeEditor() {
if (mainEditor instanceof CodeMirror) {
mainEditor.refresh();
} else {
// Load main editor
var el = document.getElementById("codifyme");
mainEditor = CodeMirror.fromTextArea(el, {
lineNumbers: true
});
mainEditor.setSize('100%', 50);
}
}
function initSecondaryCodeEditor() {
var $active = $('#code_mirror_editors > .active > a');
var $sec_tab = $($active.data('target'));
CodeMirror.fromTextArea($sec_tab.find('textarea')[0], {
lineNumbers: true
});
}
$(document).ready(function() {
// Only load editors if tab has been clicked
$('#maintabs > li > a[data-target="#codemirror"]').on('shown.bs.tab', function(e) {
initMainCodeEditor();
});
$('#code_mirror_editors > li > a[data-toggle="tab"]').on('shown.bs.tab', function(e) {
initSecondaryCodeEditor();
});
// Remember tabs
var json, tabsState;
$('a[data-toggle="tab"]').on('shown.bs.tab', function(e) {
tabsState = localStorage.getItem("tabs-state");
json = JSON.parse(tabsState || "{}");
json[$(e.target).parents("ul.nav.nav-pills, ul.nav.nav-tabs").attr("id")] = $(e.target).data('target');
localStorage.setItem("tabs-state", JSON.stringify(json));
});
tabsState = localStorage.getItem("tabs-state");
json = JSON.parse(tabsState || "{}");
$.each(json, function(containerId, target) {
return $("#" + containerId + " a[data-target=" + target + "]").tab('show');
});
$("ul.nav.nav-pills, ul.nav.nav-tabs").each(function() {
var $this = $(this);
if (!json[$this.attr("id")]) {
return $this.find("a[data-toggle=tab]:first, a[data-toggle=pill]:first").tab("show");
}
});
}); // doc.ready
})(jQuery);
The problems:
it might happen that you create the CodeMirror on an element which is not visible (one of it's parents has display: none). This breaks various calculations done by CodeMirror
by getting the CodeMirror instance right from the CodeMirror container element enables us to call refresh everytime you want (by finding the .CodeMirror next to your textarea)
fixed as a side effect of 2.
HTML
Here's a bootstrap tab frame, if you use jquery-UI, it's gonna be a little different.
<ul class="nav nav-tabs">
<li class="active">tab1</li>
<li>tab2</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade in active" id="tab1"><textarea type="text" id="tab1Content" name="xxx"></textarea></div>
<div class="tab-pane fade" id="tab2"><textarea type="text" id="tab2Content" name="yyy"></textarea></div>
</div>
JS
var cm1, cm2;
$(document).ready(function () {
//when the bootstrap tab is fully shown, call codemirror's refresh().
//Also, if you use jquery-UI, it's gonna be different here.
$('.nav-tabs a').on('shown.bs.tab', function() {
cm1.refresh();
cm2.refresh();
});
cm1 = CodeMirror.fromTextArea(document.getElementById("tab1Content"), {
lineNumbers: true
});
cm2 = CodeMirror.fromTextArea(document.getElementById("tab2Content"), {
lineNumbers: true
});
});
Working Solution: http://codepen.io/anon/pen/hupwy
I addressed issues 2 and 3 as I could not replicated 1.
I used a hash table to store the second editor CodeMirror objects. Then I modified your existing mainEditor code to refresh the objects if they already exist.
var seccondEditor = new Object();
function initSecondaryCodeEditor(){
var $active = $('#code_mirror_editors > .active > a');
var $sec_tab = $($active.data('target'));
var sec_edi = ($sec_tab.find('textarea')[0]);
if(seccondEditor[sec_edi.id] instanceof CodeMirror){
seccondEditor[sec_edi.id].refresh();
} else {
seccondEditor[sec_edi.id] = CodeMirror.fromTextArea(sec_edi, {lineNumbers: true});
}
}
I'm not well versed in CodeMirror so this might no be the most elegant solution, but it looks like the code above prevents the duplicates you were seeing. Hope this helps.
if the problem occurs when codemirror render content within an hidden div, why not just diplay all the tab-panel div, then call codemirror, then hide unneeded tab ??
HTML:
<div role="tabpanel" class="tab-pane active" id="tp1">
<textarea class="code" data-lang="text/html">
<!--- content #1 here -->
</textarea>
</div>
<div role="tabpanel" class="tab-pane active hideAfterRendering" id="tp2">
<textarea class="code" data-lang="text/html">
<!--- content #2 here -->
</textarea>
</div>
<div role="tabpanel" class="tab-pane active hideAfterRendering" id="tp3">
<textarea class="code" data-lang="text/html">
<!--- content #3 here -->
</textarea>
</div>
SCRIPT:
<script>
$( document ).ready(function() {
//render codeMirror
$('.code').each(function() {
CodeMirror.fromTextArea(this, {
mode: "properties",
lineNumbers: true,
indentUnit: 4,
readOnly: true,
matchBrackets: true
});
});
//hide tab-panel after codeMirror rendering (by removing the extra 'active' class
$('.hideAfterRendering').each( function () {
$(this).removeClass('active')
});
});
</script>
Works well for me !!
Why not just to set timeout?.. just exec that code when tab clicked:
update_mirror = function() {
var codeMirrorContainer = $sec_tab.find(".CodeMirror")[0];
if (codeMirrorContainer && codeMirrorContainer.CodeMirror) {
codeMirrorContainer.CodeMirror.refresh();
}
}
// Attention! magic!
setTimeout(update_mirror, 100);
That helped me a lot while I had a battle against that problem. Thanks to Sekaryo Shin, he saved my time.
I've got the following code that works great! When I click Link 1, the DIV content appears. When I click it again, it disappears. If I click Link 1 again, the DIV content appears again. If I click Link 2 this time, the content appears along with Link 1 content. I want Link 1 to disappear if another DIV link is clicked. I don't want to have to turn that content off before turning another one on. How do I make a DIV disappear after another one is clicked?
Javascript:
function show(ele) {
var srcElement = document.getElementById(ele);
if(srcElement != null) {
if(srcElement.style.display == "block") {
srcElement.style.display= 'none';
}
else {
srcElement.style.display='block';
}
}
return false;
}
DIV:
FIRST LINK
SECOND LINK
<div id="link1" style="display:none">
<p>Link 1 Content Displayed</p>
</div>
<div id="link2" style="display:none">
<p>Link 2 Content Displayed</p>
</div>
I don't want to change the way I'm doing this, I feel like there's a simple solution, I just can't figure it out! Any help is appreciated.
Another, better answer would be to use jQuery, because it lets you write better javascript without having to worry about whether IE is going to break.
include this tag in the head:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
Javascript:
function show( elem )
{
$('.dynamic_link').hide();
$('#'+elem).show();
}
HTML:
FIRST LINK
SECOND LINK
<div id="link1" class="dynamic_link" style="display:none">
<p>Link 1 Content Displayed</p>
</div>
<div id="link2" class="dynamic_link" style="display:none">
<p>Link 2 Content Displayed</p>
</div>
Javascript (modified):
function show(ele) {
var links = ['link1','link2'];
var srcElement = document.getElementById(ele);
var doShow = true;
if(srcElement != null && srcElement.style.display == "block")
doShow = false;
for( var i = 0; i < links.length; ++i ) {
var otherElement = document.getElementById(links[i]);
if( otherElement != null )
otherElement.style.display = 'none';
}
if( doShow )
srcElement.style.display='block';
return false;
}
working example: http://jsfiddle.net/vDKmA/
I know this has been asked a thousand times but I'm still having trouble figuring it out. I have a simple according following this tutorial and I'm trying to add an "expand/collapse all" link. I have found a way to expand all but can't figure out how to collapse them. The problem with a slideToggle() solution is if I open one then click the link it will close/open all of them but the one that was previoiusly active.
I set up a jsFiddle here.
Here is an overview of the code:
HTML:
<h2 class="acc_trigger">Div 1</h2>
<div class="acc_container">
<div class="block"> Yay content!</div>
</div>
<h2 class="acc_trigger">Div 2</h2>
<div class="acc_container">
<div class="block">More Content, Score!</div>
</div>
<h2 class="acc_trigger">Div 3</h2>
<div class="acc_container">
<div class="block">Even More Content</div>
</div>
Expand/Collapse All
JS:
jQuery(document).ready(function($) {
//Set default open/close settings
$('.acc_container').hide(); //Hide/close all containers
//On Click
$('.acc_trigger').click(function(){
$('.acc_trigger').removeClass('active').next().slideUp();
//Remove all "active" state and slide up the immediate next container
$(this).toggleClass('active').next().slideDown();
return false; //Prevent the browser jump to the link anchor
});
$('.acc_expand-all').click(function(){
//expand all on click
$('.acc_trigger').addClass('active').next().slideDown();
return false;
});
});
You have to check in your expand/collapse handler to see how many are open, etc., something like this (updated fiddle):
$('.acc_expand-all').click(function(){
var all = $('.acc_trigger'),
active = all.filter('.active');
if (all.length && all.length === active.length) {
// All open; close them
all.removeClass('active').next().slideUp();
}
else {
// At least some are closed, open all
all.not('.active').addClass('active').next().slideDown();
}
return false;
});
Regarding your question in the comments, you can check to see whether you should be in "exclusive" mode or not by checking how many are open and whether the clicked one is open, e.g. (updated fiddle):
$('.acc_trigger').click(function(){
var $this = $(this),
thisActive = $this.hasClass('active'),
active;
// If this one is active, we always just close it.
if (thisActive) {
$this.removeClass('active').next().slideUp();
}
else {
// Is there just one active?
active = $('.acc_trigger.active');
if (active.length === 1) {
// Yes, close it
active.removeClass('active').next().slideUp();
}
// Open this one
$this.addClass('active').next().slideDown();
}
});
hi i am trying to make a wizard for first time i want to disable all accordion tabs when i click on the link it enable next tab and open it..
i hve this code but it disable all tabs :(
thanks
$(function() {
$("#list1a").accordion({
autoHeight: false,
navigation: false
});
});
$("#list1a").accordion("disable");
$("#list1a").accordion("activate", 2 );
Don't use the accordion for that, it's not intended for wizardry. And since there's no wizard component available in jquery UI, lets make our own ;)
html:
<ul class="ui-wizard">
<li class="ui-wizard-panel">
<h3 class="ui-wizard-header">panel 1</h3>
<div class="ui-wizard-content">
Panel content
<span class="ui-wizard-next">Goto next</span>
</div>
</li>
<li class="ui-wizard-panel">
<h3 class="ui-wizard-header">panel 1</h3>
<div class="ui-wizard-content">
Panel content
<span class="ui-wizard-next">Goto next</span>
</div>
</li>
</ul>
javascript plugin:
$.fn.wizard = function(){
this.find('.ui-wizard-content').hide();
this.find('.ui-wizard-content:first').show();
this.find('.ui-wizard-content:last .ui-wizard-next').hide(); // just in case
this.delegate('.ui-wizard-next', 'click', function(){
// very long jquery chain...
$(this).closest('.ui-wizard-content')
.hide('fast')
.closest('.ui-wizard-panel')
.next()
.find('.ui-wizard-content')
.show('fast');
});
}
javascript impl:
$(".ui-wizard").wizard();
Ofcourse.. you'd have to theme it yourself, though copy/pasting and renaming accordion styles gets you a long way. A nicer way would be to make an official wizard widget out of this.
Can also check out this code: http://github.com/desdev/jWizard/
Think it's exactly what you need.
Try ui-state-disabled class: http://api.jqueryui.com/theming/css-framework/
Consider this piece of code that allows user go back, but not go to next accordion tab:
function disableAccordionNextTabs () {
var $accordion = $(".accordion");
var active = $accordion.accordion('option', 'active');
var $headers = $accordion.find($accordion.accordion('option', 'header'));
$headers.addClass('ui-state-disabled');
for (var i = active; i >= 0; i--) {
$headers.eq(i).removeClass('ui-state-disabled');
}
}