I've transplanted Toggling Element Visiblity from its old home on the Mindsack; kindly update your bookmarks.
Please do read the source; it's all obsessively commented and ought to be pretty self-explanatory. Here are some of the highlights:
toggle. If we find one that says toggle closed, we immediately hide its next sibling element, by styling it with class name hidden.toggle, closed, and hidden) are fed in at the bottom in the init call, and may be changed to any valid class name.That's it! With only a single global variable we're making a good-faith attempt to stay out of the general namespace, and we're not capturing any far-reaching events like document.onmousedown so it ought to work and play nicely with other scripts. Naturally you should feel free to change my KENTBREW.toggle object namespace to whatever you like.
<html> <head> <title>My Toggled Page</title> <link rel="stylesheet" type="text/css" href="toggle.css" /> </head> <body> <dl> <dt class="toggle">This is an open headline.</dt> <dd>This will hide if the headline above is toggled.</dd> <dt class="toggle closed">This is a closed headline</dt> <dd>This will show if the headline above is toggled.</dd> </dl> <script type="text/javascript" src="toggle.js"></script> </body> </html>
.toggle {
background: transparent url('norgie_open.gif') .25em .25em no-repeat;
text-indent: 20px;
cursor:pointer;
}
.toggle.closed {
background: transparent url('norgie_closed.gif') .25em .25em no-repeat;
}
.hidden {
display:none;
}
// toggling event visibility
// v5 Kent Brewster, 7/11/2006
// questions? comments? dirty jokes?
// please leave 'em here:
// http://kentbrewster.com/toggle
// feel free to use or abuse this code
// but please leave this notice intact
// namespace protection: one global variable to rule them all
var KENTBREW = window.KENTBREW || {};
KENTBREW.toggle = function() {
// private bucket for scope-sensitive variables -- thanks, Dustin
var $ = {};
return {
init : function(selfObj, toggleClass, toggleClosed, toggleHidden) {
// first, a brute-force hack to decode the calling function's
// name and store it upstairs, safe from scope creep
$.selfName = this.getSelfName(selfObj);
// we're going to hang all variables that might be confused
// by scope changes later onto KENTBREW.variables, which is aliased to $.
// In this case it's three class names, fed in from the init call:
$.toggleClass = toggleClass;
$.toggleClosed = toggleClosed;
$.toggleHidden = toggleHidden;
// crawl through the document, look for toggled elements
this.crawl(document.body);
},
crawl : function(el) {
// get this element's next sibling
var nextSib = this.getNextSibling(el);
// if it has a class name, the class name matches our toggle class, and there's something there to toggle:
if (el.className && el.className.match($.toggleClass) && nextSib)
{
// to avoid scope loss, attach onmouseup to the toggle function with eval and $.selfName
el.onmouseup = function () {
eval($.selfName + '.toggleState(this)');
};
// if the next sib ought to be hidden and it isn't already, hide it
if (el.className.match($.toggleClosed) && nextSib && !nextSib.className.match($.toggleHidden)) {
nextSib.className += ' ' + $.toggleHidden;
}
}
// is there more to do? Do it, if so:
if (el.firstChild) {
this.crawl(el.firstChild);
}
if (nextSib) {
this.crawl(nextSib);
}
},
toggleState : function(el) {
// change the style of the triggering element
if(el.className.match($.toggleClosed)) {
el.className = el.className.replace($.toggleClosed, '');
}
else {
el.className = el.className + ' ' + $.toggleClosed;
}
// the norgie we clicked has changed. Now we need to
// change the style of its parent node's next sibling
var nextSib = this.getNextSibling(el);
// check if it's really there; other scripts could have removed it
if(nextSib && nextSib.className.match($.toggleHidden)) {
nextSib.className = nextSib.className.replace($.toggleHidden, '');
}
else {
nextSib.className += ' ' + $.toggleHidden;
}
},
getNextSibling : function(el) {
var nextSib = el.nextSibling;
// hack for Gecko browsers
if (nextSib && nextSib.nodeType != 1) {
nextSib = nextSib.nextSibling;
}
return nextSib;
},
getSelfName : function(selfObj) {
// icky hack to get contents of selfObj into a string
// suggestions will be gratefully appreciated
var s = document.createElement('SPAN');
s.innerHTML = selfObj;
// cut the fat, split the meat to namespace array
var nameSpace = s.innerHTML.split('{')[1].split('(')[0].replace(/^\s+/, '').split('.');
var selfName = '';
// here we assume that the main function is up one level from the init function
for (var i = 0; i < nameSpace.length - 1; i++) {
if (selfName) {
selfName += '.';
}
selfName += nameSpace[i];
}
return selfName;
}
};
}();
// feed it the CSS class names of your choice
window.onload = function() {
KENTBREW.toggle.init(arguments.callee, 'toggle', 'closed', 'hidden');
}();
I just had a need to toggle and immediatly thought of this post. So I shamelessly cut and pasted into my site, but had a little trouble with your code. For some reason not exactly clear to me the document.body was null using your event handler. So I added the event handler I use (modified slightly from Resig), and it seems to suit my needs.
Thanks for the resource.
Terry Riegel
observe: function( obj, type, fn ) {
if (!(obj['observing'+type])){
if ( obj.attachEvent ) {
obj['e'+type+fn] = fn;
obj[type+fn] = function(){obj['e'+type+fn]( window.event );};
obj.attachEvent( 'on'+type, obj[type+fn] );
} else {
obj.addEventListener( type, fn, false );
}
obj['observing'+type]=true;
}
}
// feed it the CSS class names of your choice
KENTBREW.toggle.observe(window,'load',function() {KENTBREW.toggle.init(arguments.callee, 'toggle', 'closed', 'hidden');});
I have to say that i am very fond of this technique and i love to employ it myself.
However i am not a coder as such and would very much like to see an adaptation of this method that automatically hides all OTHER "Drop Downs" when ever a "Drop Down" is activated!
I would prefer this method for tidyness and also for the fact that i believe it is more intuitive as these drop downs are like "Draws" in a filing cabinet and who opens all their draws at once? No one....
If you can help i belive this would jazz it up a bit...also as an added nicety i have included (in my own script)an adaptation/add on to this basic idea that does inhance it visually somewhat and that is to combine it with a mouse flyover effect to switch your "handle icon" (to an animated gif) which is a nice touch. The code i used for this rollover I got from here:
"http://scriptasylum.com/tutorials/rollovers/rollovers.html" this code is the best as it does not require seperate code in the script for each instance....
Also i find it is cool to use A DSS Style from your tag that encloses the text and the icon so that placing your mouse over either the text or the icon causes the icon animation to proceed as well as changing the text color of the text like a link(also having the text underlined too)... both these devices i think are logical as clicking on a heading/icon to drop down a table is (in the mind of the user) the same as clicking on a link...
And having the text highlight on flyover as well as the animation also serves to remind the user that there is something that can be clicked on...which then greatly lessens the problem of people not realizing the hidden content.
if(el.className.match($.toggleClosed)) {
el.className = el.className.replace($.toggleClosed, '');
} else {
el.className = el.className + ' ' + $.toggleClosed;
}
We're saying "If you see the closed toggle class, remove it. If you don't, add it." Make sense?
In my stylesheet it says ".toggle.closed" (class toggle class closed?)
Yet in my HTML I get class="toggle closed" (no period in between)
at the very end of the javascript it says " 'toggle', 'closed', 'hidden');"
I'm having trouble understanding the relationship between these. I don't know any Javascript, but I have a firm knowledge of css and html.
What I'm trying to do is use this script for both my news and my navigation menu, but since I don't fully understand what's going on, I'm having a hard time doing so.
Where in your Javascript do you say (in human language) "Dear script, please change the class "toggle" to "toggle closed""?
var myTag = 'A';
var thePossibles = document.getElementsByTagName(myTag);
Loop through thePossibles, check for the class name, and apply the toggle logic--the part in function crawl(), where we match the className--if it appears.
too much recursion
var nextSib = this.getNextSibling(el);
http://www.shopmicrofiber.com/what-is-Microfiber.asp
Adam