From: Kameleonten on
To make my navigation menu work in IE I have used this script. But it
doesn't work with classes. So when I now want to use a CMS that
genererates the navigation hierarchy that uses class instead of ID it
fails. How do I modify it so it works with CLASS instead of ID?

startList = function() {
if (document.all && document.getElementById) {
navRoot = document.getElementById("nav");
for (i=0; i<navRoot.childNodes.length; i++) {
node = navRoot.childNodes[i];
if (node.nodeName=="LI") {
node.onmouseover=function() {
this.className+=" over";
}

node.onmouseout=function() {
this.className=this.className.replace(" over", "");
}
}
}
}
}
window.onload=startList;

----------------------------------------

Here is my experiment that doesn't work:

function getElementbyClass(classname){
var partscollect;

var inc=0
var alltags=document.all? document.all :
document.getElementsByTagName("*")

for (i=0; i<alltags.length; i++){
if (alltags[i].className==classname)
partscollect=alltags[i]
}
}


startList = function(){

if (document.all && document.getElementByClass) {
navRoot = document.getElementByClass("bulletmenu");

for (i=0; i < navRoot.partscollect.childNodes.length; i++) {
node = navRoot.partscollect.childNodes[i];
if (node.nodeName=="LI") {
node.onmouseover=function() {
this.className+=" over";
}

node.onmouseout=function() {
this.className=this.className.replace(" over", "");
}
}
}
}
}

I don't have any javascript experience, but with Java I have .

From: Randy Webb on
Kameleonten said the following on 12/20/2005 8:14 PM:
> To make my navigation menu work in IE I have used this script. But it
> doesn't work with classes. So when I now want to use a CMS that
> genererates the navigation hierarchy that uses class instead of ID it
> fails. How do I modify it so it works with CLASS instead of ID?
>
> startList = function() {
> if (document.all && document.getElementById) {
> navRoot = document.getElementById("nav");
> for (i=0; i<navRoot.childNodes.length; i++) {
> node = navRoot.childNodes[i];
> if (node.nodeName=="LI") {
> node.onmouseover=function() {
> this.className+=" over";

It may or may not be the source of your problem. But, className's can
not contain a space. What you are doing in the onmouseover is adding "
over" to the className. That contains a space and will cause a problem.
might try: this.className+="over";

Also, if your classNames onmouseover will always have over appended to
the end, it might be better to simply remove the last 4 characters from
the className than to remove the sequence "over" from the className. If
the className is "myHoverClass" when you add "over" to it, it becomes
"myHoverClassover" and removing over will remove the first one, not the
last one so it becomes "myHClassover".

Or, change the remove to match the last one, not the first one.

--
Randy
comp.lang.javascript FAQ - http://jibbering.com/faq & newsgroup weekly
Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
From: Thomas 'PointedEars' Lahn on
Kameleonten wrote:

> To make my navigation menu work in IE I have used this script. But it
> doesn't work with classes. So when I now want to use a CMS that
> genererates the navigation hierarchy that uses class instead of ID it
> fails. How do I modify it so it works with CLASS instead of ID?
>
> startList = function() {
^^^^^^^^^
Undeclared global variable.

> if (document.all && document.getElementById) {

This does not make sense. You are not even using document.all,
yet testing for it. What should that accomplish anyway?

<URL:http://pointedears.de/scripts/test/whatami#inference>

> navRoot = document.getElementById("nav");
^^^^^^^
> for (i=0; i<navRoot.childNodes.length; i++) {
^
> node = navRoot.childNodes[i];
^^^^
Undeclared global variables.

> if (node.nodeName=="LI") {

Use HTMLElement::tagName instead.

> node.onmouseover=function() {
> this.className+=" over";

If the `class' attribute value of that element was empty before (default),
the new value could end up to be not Valid. HTML 4.01 defines the `class'
attribute value as a whitespace separated list of non-whitespace CDATA:

<URL:http://www.w3.org/TR/html4/struct/global.html#adef-class>

Also note that the specificity of a previously declared selector defines
whether changing `class' attribute value/className property has any effect
on the stylesheet cascade.

<URL:http://www.w3.org/TR/CSS2/cascade.html>

> }
>
> node.onmouseout=function() {
> this.className=this.className.replace(" over", "");
> }
> }
> }
> }
> }
> window.onload=startList;

Assign event listeners using EventTarget::addEventListener()
[W3C DOM Level 2 Events] or eventTarget.attachEvent() [IE DOM],
if possible.

Indent (especially posted) code using spaces, not tabs.
Corrected and pretty-printed, that is

....
<html>
<head>
...
<meta http-equiv="Content-Script-Type" content="text/javascript">
<script type="text/javascript">
/**
* @author
* (C) 2003, 2004 Thomas Lahn &lt;types.js(a)PointedEars.de&gt;
* @partof
* http://pointedears.de/scripts/types.js
*/
function dhtml_isMethodType(s)
{
return (s == "function" || s == "object");
}

/*
* @author
* (C) 2004 Thomas Lahn &lt;dhtml.js(a)PointedEars.de&gt;
* @partof
* http://pointedears.de/scripts/dhtml.js
*/
function registerEvent(o, sEvent, fListener, bUseCapture)
{
var result;

if (o)
{
if (dhtml_isMethodType(typeof o.addEventListener)
&& dhtml_isMethodType(typeof fListener))
{
o.addEventListener(sEvent, fListener, !!bUseCapture);
result = true;
}
else if (dhtml_isMethodType(typeof o.attachEvent)
&& dhtml_isMethodType(typeof fListener))
{
result = o.attachEvent("on" + sEvent, fListener);
}
else
{
o["on" + sEvent] = fListener;
result = (o["on" + sEvent] == fListener);
}
}

return result;
}

function startList()
{
if (isMethodType(typeof document.getElementById))
{
var navRoot = document.getElementById("nav");
if (navRoot && navRoot.childNodes)
{
for (var i = 0; i < navRoot.childNodes.length; i++)
{
var node = navRoot.childNodes[i];
if (node.tagName.toLowerCase() == "li")
{
node.onmouseover=function()
{
if (this.className)
{
this.className = this.className.replace(/\s*$/, " over");
}
else
{
this.className = "over";
}
}

registerEvent(node, 'mouseout',
function()
{
this.className = this.className.replace(/\s*over/, "");
});
}
}
}
}
}
</script>
</head>

<body onload="startList()">
...
</body>
</html>

> ----------------------------------------
>
> Here is my experiment that doesn't work:
>
> function getElementbyClass(classname){
> var partscollect;
>
> var inc=0

Unused variable.

> var alltags=document.all? document.all :
> document.getElementsByTagName("*")

You want to test whether `document.getElementsByTagName' refers to a
method before you call it. See above.

> for (i=0; i<alltags.length; i++){
^ ^^^^^^^^^^^^^^ inefficient
Undeclared global variable.

> if (alltags[i].className==classname)
> partscollect=alltags[i]

That would overwrite the previous value of partscollect with a reference
to the object referred to by `alltags[i]', therefore the function does not
return a collection as implied by your use of the method below.

> }
> }

As I said, the value of the `class' attribute, thus the value of the
`className' property, is a whitespace-separated list of non-whitespace
CDATA. The condition above will only apply if that list has only one
element. It should be

var aResult = [];

if (alltags && alltags.length)
{
for (var i = 0, len = alltags.length; i < len; i++)
{
var o = alltags[i];
if (new RegExp("\\b" + classname + "\\b")
.test(o.className))
{
aResult.push(o);
}
}
}

With the provision that the value of `classname' may not contain unescaped
characters considered special in RegExp. If it does and matching such
"wildcard" attribute values is not desired, the value of `classname' has
to be escaped properly before it can be used in the RegExp() argument.

> startList = function(){
^^^^^^^^^
See above.

> if (document.all && document.getElementByClass) {

The document.all test is again bogus.

And globally declared functions, such as your `getElementByClass', do not
automatically become properties of the (HTMLDocument) object referred to
by `document'. If you want that, you have to do

document.getElementByClass = functionReference;

before. Test with

if (dhtml_isMethodType(typeof getElementByClass))
{

otherwise.

> navRoot = document.getElementByClass("bulletmenu");
^^^^^^^
See above.

> for (i=0; i < navRoot.partscollect.childNodes.length; i++) {
^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^[1]
See above.

[1] This cannot work. If your getElementByClass() method worked as
intended, `navRoot' would refer to that collection. `partscollect'
is clearly defined locally through the `var' keyword. You are mixing
up contexts.

> node = navRoot.partscollect.childNodes[i];
^^^^
> [...]

See above.

> I don't have any javascript experience, but with Java I have .

In Java, the concept of execution context is much more strictly implemented
than in J(ava)Script/ECMAScript, so you should have noticed that.


HTH

PointedEars
From: Thomas 'PointedEars' Lahn on
Randy Webb wrote:

> [...] But, className's can not contain a space.

They certainly can, see my other followup.


PointedEars
From: Thomas 'PointedEars' Lahn on
Kameleonten wrote:

> [...]
> Here is my experiment that doesn't work:
> [...]

"Does not work" is a useless error description. [psf 4.11]

<URL:http://jibbering.com/faq/#FAQ4_43>


PointedEars
 |  Next  |  Last
Pages: 1 2
Prev: scroll select
Next: How to rotate the image