Forum Moderators: open
Hide / Show (Toggle)
<p><a href="JavaScript:;" onmousedown="if (document.getElementById('content').style.display == 'none') {document.getElementById('content').style.display = 'block';} else {document.getElementById('content').style.display = 'none';}">Hide / Show (Toggle)</a></p>
<p><a href="JavaScript:;" onmousedown="document.getElementById('content').style.display = 'none'">Hide</a></p>
<p><a href="JavaScript:;" onmousedown="document.getElementById('content').style.display = 'block'">Show</a></p>
<div id="content" style="display:none;">DIV containing the hidden content</div>
Any feedback welcome :)
Any feedback welcome :)
Ya sure? :-P
<a href="JavaScript:;" onmousedown . . . .
Javascript is not a URL. This is important.
Also I've never even tried onmousedown, it's valid in Flash AS, but not even sure if that works (guess it does, by your testimonial . . )
Here's what you can do to make the links accessible and externalize the scripting, which is a good start.
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01
Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!-- doctype on one line -->
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Untitled</title>
<script type="text/javascript">
window.onload=function() {
if ((document.getElementById('open_div')) &&
(document.getElementById('content'))) {
// For various reasons . . .
document.getElementById('content').style.display='none';
// Adding a var so the page doesn't explode in the forum
var obj = document.getElementById('open_div');
obj.onclick=function() {
var o = document.getElementById('content');
o.style.display=(o.style.display=='block')?'none':'block';
obj.innerHTML=(o.style.display=='block')?'See Less':'See More...';
return false;
};
}
}
</script>
</head>
<body>
<p><a href="alternate_content.html" id="open_div">See More . . .</a></p>
<div id="content">DIV containing the hidden content</div>
</body>
</html>
Edit:
Also it's extremely compact, saving all the extra scripts in the head space.
1. href="JavaScript:;"
There is no such thing as a "JavaScript:" protocol. The href attribute [w3.org] is supposed to take a URI value, so the value "JavaScript:;" is NOT a valid URI. In addition to being technically wrong, it is also inaccessible. Users and search engines that don't have JavaScript enabled will be presented with a totally useless link, which is just bad practice.
2. onmousedown="..."
This also adds to the accessibility issue. Users who navigate with the keyboard only will not trigger the onmousedown event. Instead, use the onclick event handler, which will be triggered for both keyboard navigation and mouse navigation.
3. By using inline event handlers, you are losing the benefits of unobtrusive JavaScript. A better approach would be to separate your content (HTML) from behavior (JavaScript). This allows for a much more "pure" web page, and will make maintenance easier because all of your behavior functionality will be found in JavaScript files (you won't need to dig through a bunch of HTML code to find all of your behavior functionality).
4. That is not what I would consider "compact". If you have several of these on a page, you're bloating your HTML and not taking advantage of code reuse. In addition, the <head> is not the ideal place for JavaScript either. JavaScript is best kept in a separate .js file, and included in the document just before the closing </body>.
5. Because the hide/show links are purely client side (that is, they are not really content, they merely "enhance" the content), I would not include the actual links in my markup, but would instead generate them using JavaScript. This is "progressive enhancement", providing a base page that is accessible to all, and then enhancing it for those with browsers that can make use of the enhancement. This will give you a totally accessible page and keep your markup light.
Based on those comments, here is how I would change your example. I would remove the link from the markup altogether. I would create a class that allowed me to easily create an object representation of the toggler, so I could do something like:
var x = new Toggler('content');
where 'content' is the id of the div to toggle. The markup would then be simplified to something like this:
<div id="content">
DIV containing the hidden content. Note, this is
not hidden until the progressive enhancement hides
it (it remains accessible to those without
JavaScript, including search engines).
</div>
...
<script type="text/javascript" src="myscript.js"></script>
</body>
</html>
Note, the script is included just before the closing </body> tag.
If I have some time, I'll try to throw together an example.
<!DOCTYPE html>
<html>
<head>
<title>Toggler Test</title>
</head>
<body>
<div id="article1">
This article will be <strong>hidden</strong>
by default and can only be <strong>shown</strong>.
</div>
<div id="article2">
This article will be <strong>shown</strong>
by default and can only be <strong>hidden</strong>.</div>
<div id="article3">
This article can be <strong>toggled</strong>
So it will be <strong>hidden</strong> by default.
</div>
<div id="article4">
This article will be shown no matter what.
</div>
<script type="text/javascript">
// Wrap the script in a self-executing anonymous function to
// prevent tainting the global environment
(function () {
/**
* Makes an element able to be toggled between a hidden and
* visible state (by setting the display style attribute).
* It creates a link before the element to be toggled.
* @param id {String} The id of the element to show/hide
* @param type {String} Specifies whether this will
* "show", "hide", or "toggle" (default "toggle") the element.
* Note, elements with "show" or "hide" are essentially
* one-time-use only.
*/
function Toggler(id, type) {
var t = (type ? type : 'toggle'), // get the type
that = this, // reference to this object for event handler
div, a; // the elements we'll create
if (t != 'toggle' && t != 'show' && t != 'hide') {
t = 'toggle'; // Make sure t is a valid type
}
this._node = document.getElementById(id);
if (this._node) { // if node not found, nothing more will happen
div = document.createElement('div');
a = document.createElement('a');
a.href = '#' + id;
switch (t) {
case 'show':
a.innerHTML = 'Show...';
this._node.style.display = 'none';
this._shown = false;
a.onclick = function () {
if (!(that._shown)) {
that._node.style.display = '';
that._shown = true;
}
};
break;
case 'hide':
a.innerHTML = 'Hide...';
this._node.style.display = '';
this._shown = true;
a.onclick = function () {
if (that._shown) {
that._node.style.display = 'none';
that._shown = false;
}
};
break;
case 'toggle':
a.innerHTML = 'Show...';
this._node.style.display = 'none';
this._shown = false;
a.onclick = function () {
if (that._shown) {
that._node.style.display = 'none';
this.innerHTML = 'Show...';
}
else {
that._node.style.display = '';
this.innerHTML = 'Hide...';
}
that._shown = !(that._shown);
};
break;
}
div.appendChild(a);
this._node.parentNode.insertBefore(div, this._node);
}
}
// Create instances of Toggler
var a1 = new Toggler('article1', 'show'),
a2 = new Toggler('article2', 'hide'),
a3 = new Toggler('article3');
})();
</script>
</body>
</html>