jQuery toggle with cookies: how to get collapsed state by default and remain accessible?
I am a total beginner, so excuse my inability to see an obvious solution (if there is one). That said, I have scoured the interweb for an answer to this and have only run into the same question. What I've got working so far: using what I found at http://www.tobypitman.com/multiple-collapsable-panels-with-cookies/, I've managed to get multiple containers to toggle between display:block
and display:none
, and I'm setting cookies with Klaus Hartl's cookie.js.
Everything works terrifically! Except that I want the toggle containers' initial state to be closed. I'd really like to accomplish this without having any display:none
directly in the CSS, so the content remains accessible with JS off. I'm not a programmer, and my brute force method of changing things here and there until something happens is not quite cutting it. I've included the HTML, CSS and jQuery all below - the only thing that will be missing from my example is the CSS image sprite for the <h6>
that serves as the trigger.
Toggle with cookie
<style>
.toggle-wrapper {
overflow:hidden;
display:block;
}
.toggle-wrapper .toggle-container {
position:relative;
overflow: hidden;
}
.toggle-wrapper h6.trigger {
background: transparent url(images/trigger-sprite.png) no-repeat left top;/*sprite is 15x30px - plus sign on top, minus on bottom*/
height: 15px;/*half of sprite's height*/
cursor:pointer;
padding:0 0 0 16px;
margin:0;
}
.toggle-wrapper h6.active {
background-position: left bottom;/*this is the open state, showing the minus sign part of sprite*/
padding:0 0 0 16px;
}
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
/**
* Get the value of a cookie with the given key.
*
* @example $.cookie('the_cookie');
* @desc Get the value of a cookie.
*
* @param String key The key of the cookie.
* @return The value of the cookie.
* @type String
*
* @name $.cookie
* @cat Plugins/Cookie
* @author Klaus Hartl/klaus.hartl@stilbuero.de
*/
jQuery.cookie = function (key, value, options) {
// key and value given, set cookie...
if (arguments.length > 1 && (value === null || typeof value !== "object")) {
options = jQuery.extend({}, options);
if (value === null) {
options.expires = -1;
}
if (typeof options.expires === 'number') {
var days = options.expires, t = options.expires = new Date();
t.setDate(t.getDate() + days);
}
return (document.cookie = [
encodeURIComponent(key), '=',
options.raw ? String(value) : encodeURIComponent(String(value)),
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
options.path ? '; path=' + options.path : '',
options.domain ? '; domain=' + options.domain : '',
options.secure ? '; secure' : ''
].join(''));
}
// key and possibly options given, get cookie...
options = value || {};
var result, decode = options.raw ? function (s) { return s; } : decodeURIComponent;
return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? decode(result[1]) : null;
};
// http://www.tobypitman.com/multiple-collapsable-panels-with-cookies/
$(document).ready(function(){
$("div.toggle-wrapper h6").addClass("active");
var l = $('div.toggle-wrapper h6').length;
var panel = 开发者_运维技巧$("div.toggle-wrapper div.toggle-container");
for (c=0;c<=l;c++){
var cvalue = $.cookie('panel' + c);
if ( cvalue == 'closed' + c ) {
$(panel).eq(c).css({display:"none"});
$(panel).eq(c).prev().removeClass('active').addClass('inactive');
};
};
$("div.toggle-wrapper h6.active").toggle(
function () {
var num = $("div.toggle-wrapper h6").index(this);
var cookieName = 'panel' + num;
var cookieValue = 'closed' + num;
$(this).next("div.toggle-container").slideUp(500);
$(this).removeClass('active');
$.cookie(cookieName, cookieValue, { path: '/', expires: 10 });
},
function () {
var num = $("div.toggle-wrapper h6").index(this);
var cookieName = 'panel' + num;
$(this).next("div.toggle-container").slideDown(500);
$(this).addClass("active");
$.cookie(cookieName, null, { path: '/', expires: 10 });
}
);
$("div.toggle-wrapper h6.inactive").toggle(
function () {
var num = $("div.toggle-wrapper h6").index(this);
var cookieName = 'panel' + num;
$(this).next("div.toggle-container").slideDown(500);
$(this).addClass("active");
$(this).removeClass('inactive');
$.cookie(cookieName, null, { path: '/', expires: 10 });
},
function () {
var num = $("div.toggle-wrapper h6").index(this);
var cookieName = 'panel' + num;
var cookieValue = 'closed' + num;
$(this).next("div.toggle-container").slideUp(500);
$(this).removeClass('active');
$.cookie(cookieName, cookieValue, { path: '/', expires: 10 });
}
);
});
</script>
<div class="toggle-wrapper"> <h6 class="trigger">Trigger 1</h6> <div class="toggle-container"> <p>Stuff goes inside of here</p> <p>More stuff</p> <p>More even</p> </div> </div> <div class="toggle-wrapper"> <h6 class="trigger">Trigger 2</h6> <div class="toggle-container"> <p>Stuff goes inside of here</p> <p>More stuff</p> <p>More even</p> </div> </div> <div class="toggle-wrapper"> <h6 class="trigger">Trigger 3</h6> <div class="toggle-container"> <p>Stuff goes inside of here</p> <p>More stuff</p> <p>More even</p> </div> </div>
To create a closed default state, just make the toggle-container depend on another cookie called let's say 'open'. If there is no cookie 'open + c' the container is hidden as well.
if ( cvalue == 'closed' + c || cvalue != 'open' + c ){
//hide()etc...
}
Now don't make the toggle function remove the panel cookie on slideDown, but set the panel cookie with value 'open + num'.
var cookieValue = 'open' + num;
$.cookie(cookieName, cookieValue, { path: '/', expires: 10 });
After setting the open cookie the script works like it did before. Here is the whole thing with different class names but that should not be a problem.
$(document).ready(function(){
// Toggle sliding containers with cookies
$("div.toggle_widget h2.toggle_trigger").addClass("active");
var l = $('div.toggle_widget h2.toggle_trigger').length;
var panel = $("div.toggle_widget div.toggle_container");
for (c=0;c<=l;c++){
var cvalue = $.cookie('panel' + c);
if ( cvalue == 'closed' + c || cvalue != 'open' + c ) {
$(panel).eq(c).css({display:"none"});
$(panel).eq(c).prev().removeClass('active').addClass('inactive');
};
};
$("div.toggle_widget h2.toggle_trigger.active").toggle(
function () {
var num = $("div.toggle_widget h2.toggle_trigger").index(this);
var cookieName = 'panel' + num;
var cookieValue = 'closed' + num;
$(this).next("div.toggle_container").slideUp(250);
$(this).removeClass('active');
$.cookie(cookieName, cookieValue, { path: '/', expires: 10 });
},
function () {
var num = $("div.toggle_widget h2.toggle_trigger").index(this);
var cookieName = 'panel' + num;
var cookieValue = 'open' + num;
$(this).next("div.toggle_container").slideDown(250);
$(this).addClass("active");
$.cookie(cookieName, cookieValue, { path: '/', expires: 10 });
}
);
$("div.toggle_widget h2.toggle_trigger.inactive").toggle(
function () {
var num = $("div.toggle_widget h2.toggle_trigger").index(this);
var cookieName = 'panel' + num;
var cookieValue = 'open' + num;
$(this).next("div.toggle_container").slideDown(250);
$(this).addClass("active");
$(this).removeClass('inactive');
$.cookie(cookieName, cookieValue, { path: '/', expires: 10 });
},
function () {
var num = $("div.toggle_widget h2.toggle_trigger").index(this);
var cookieName = 'panel' + num;
var cookieValue = 'closed' + num;
$(this).next("div.toggle_container").slideUp(250);
$(this).removeClass('active');
$.cookie(cookieName, cookieValue, { path: '/', expires: 10 });
}
);
});
The problem you're trying to solve is how to hide content visually without making it inaccessible to screen readers. There are a number of ways to do this; the most up-to-date (as of July 2011) is the clip method. Here:
.hidden {
position: absolute !important;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
padding: 0 !important;
border: 0 !important;
height: 1px !important;
width: 1px !important;
overflow: hidden;
}
If you like, you can read more about it in the article When and How to Visually Hide Content on Design Festival, which discusses some of the older methods as well.
Also, note that the slideUp jQuery method assigns display: none
to its target on completion, which will render it unavailable to screen readers until the panel is revealed again. That may not be a problem in your specific case. However, if it bothers you, you can add a callback function to slideUp which resets display to block and adds the hidden class so that AFTER the panel is off screen, it is once more made available to screen readers.
精彩评论