...

View Full Version : Walking DOM, changing <a> classes



mindlessLemming
08-10-2004, 02:01 AM
Hey :)
I'm working on my first little JS related project and I need the help of a DOM concious coder please.
The Deal
I have a series of 3 modules that are only being displayed one at a time - upon selection of the link to activate one it hides the rest.
These modules each have 3 sub-modules which are also being displayed one at a time, with the links to choose the active one within the parent module (div).

That stuff's all good, but what I need help with is setting the class of the <a> that has just been clicked to "active" and making sure that no other link within the same module is also assigned class="active".
The parent link of the chosen module will need to active also, so I can't just go through the whole page removing any instance of class="active"
When one of the three parent modules is activated, it also activates the first of it's children, so I also need to assign class="active" to the first <a> child of the parent div.
Here's my JS for the show/hide stuff (not x-browser yet ;))


<script type="text/javascript">
mod=new Array()
mod[0]="ssm-hits"
mod[1]="ssm-user"
mod[2]="ssm-refer"

hits=new Array()
hits[0]="ss-hits"
hits[1]="ss-last-week"
hits[2]="ss-resources"

user=new Array()
user[0]="ss-platform"
user[1]="ss-browser"
user[2]="ss-lang"

refer=new Array()
refer[0]="ss-refer"
refer[1]="ss-repeat"
refer[2]="ss-search"

function hideexcept(elm, arr) {
for (var i = 0; i < arr.length; i++) {
var layer = document.getElementById(arr[i]);
if (elm!= arr[i]) {
layer.style.display = "none";
}
else {
layer.style.display = "block";
}
}
}
</script>


The 'mod' array is the parent of the other three arrays.
Here is a working, unstyled version of the page:
http://leftjustified.net/staticModule.html

As always, help is greatly appreciated :D

neofibril
08-11-2004, 07:02 AM
In theory, this is useable w/ scripting disabled... :)


<html>
<head>
<title>Left Justified: Statistics</title>

<style type="text/css">
.active1
{
font:caption;
color:inactivecaptiontext;
background:inactivecaption;
border:1px outset;
padding:0 .25em 0 .25em;
}
.active2
{
font:caption;
color:captiontext;
background:activecaption;
border:1px outset;
padding:0 .25em 0 .25em;
}
</style>

<script type="text/javascript">

window.onload = function()
{
var divs = document.getElementsByTagName("DIV"),
n = divs.length,
i = -1,
at;
while(++i < n)
{
at = divs[i];
if(!at.getAttributeNode("hideme"))
continue;
at.style.display = "none";
}

}

var arr = [];
function syncClass(e, top)
{
var ele = (e.target ? e.target : e.srcElement),
ar0 = arr[0],
ar1 = arr[1],
ar2 = arr[2],
stl;
if(ele.nodeName != "A")
return false;
var ref = document.getElementsByTagName("A")[ele.hash.substr(1)];
if(top)
{
if(ar1)
ar1.className = "";
ref.className = "active2";
arr[1] = ref;
ar1 = arr[1];
if(ele != ar0)
{
if(ar0)
ar0.className = "";
ele.className = "active1";
arr[0] = ele;
ar0 = arr[0];
ele = ref;
if(ar2)
ar2.display = "none";
}
stl = ref.parentNode.parentNode.parentNode.style;
stl.display = "";
arr[2] = stl;
ref = document.getElementsByTagName("A")[ref.hash.substr(1)];
}
if(ele != ar1 && ele != ar0)
{
ar1.className = "";
ele.className = "active2";
arr[1] = ele;
}
stl = ref.parentNode.parentNode.style;
if(!arr[3])
arr[3] = stl;
arr[3].display = "none";
stl.display = "";
arr[3] = stl;
}
</script>

</head>
<body>
<ul onclick="syncClass(event, 1)">
<li><a href="#serstats">Server Stats</a></li>
<li><a href="#usertats">User Stats</a></li>
<li><a href="#refstats">Referrer Stats</a></li>
</ul>

<div hideme>
<ul onclick="syncClass(event, 0)">
<li><a name="serstats" href="#serstats1">Site Hits</a></li>
<li><a href="#serstats2">Hits this Week</a></li>
<li><a href="#serstats3">Resources</a></li>
</ul>
<div hideme>
<h3><a name="serstats1">Hits <span>Uniques</span></a></h3>
<p>serstats1 data...</p>
</div>

<div hideme>
<h3><a name="serstats2">Hits in the last week</a></h3>
<p>serstats2 data...</p>
</div>

<div hideme>
<h3><a name="serstats3">Resources <span>Hits</span></a></h3>
<p>serstats3 data...</p>
</div>
</div>

<div hideme>
<ul onclick="syncClass(event, 0)">
<li><a name="usertats" href="#usertats1">Platform</a></li>
<li><a href="#usertats2">Browser</a></li>
<li><a href="#usertats3">Language</a></li>
</ul>
<div hideme>
<h3><a name="usertats1">Platform <span>%</span></a></h3>
<p>usertats1 data...</p>
</div>

<div hideme>
<h3><a name="usertats2">Browser <span>%</span></a></h3>
<p>usertats2 data...</p>
</div>

<div hideme>
<h3><a name="usertats3">Languages <span>%</span></a></h3>
<p>usertats3 data...</p>
</div>
</div>

<div hideme>
<ul onclick="syncClass(event, 0)">
<li><a name="refstats" href="#refstats1">Recent Referrers</a></li>
<li><a href="#refstats2">Repeat Referrers</a></li>
<li><a href="#refstats3">Search Strings</a></li>
</ul>
<div hideme>
<h3><a name="refstats1">Recent Referrers <span>When</span></a></h3>
<p>refstats1 data...</p>
</div>

<div hideme>
<h3><a name="refstats2">Repeat Referrers <span>Hits</span></a></h3>
<p>refstats2 data...</p>
</div>

<div hideme>
<h3><a name="refstats3">Search Strings <span>Hits</span></a></h3>
<p>refstats3 data...</p>
</div>
</div>
</body>
</html>



edit:// oops, found a bug (as usual); I'll fix that...

Ok, it all seems to work now! :cool:

mindlessLemming
08-11-2004, 08:34 AM
:eek::eek:
I can't even begin to understand that.. :o
Thankyou so much! Unfortunately, it doesn't work once the content is in there due to this (i think)

document.getElementsByTagName("DIV")

There are other divs within the hidden divs that aren't being revieled.
I was originally adapting this: http://www.alistapart.com/d/eatcake/5.html
but it had the same problem.
Oh well, guess it's back to the ol' drawing board for this one. (at least until I get half a clue about javascript!)

Thanks again :)

neofibril
08-11-2004, 08:43 AM
That's probably a minor thing to fix; I should have tried it with your full demo page, huh. :o

Is that something you'd like me to correct, or are there other probs w/ the example?

neofibril
08-11-2004, 09:20 AM
- had to change getAttributeNode("hideme") to atttibutes["hideme"]


Hopefully, this is the one: :D


<html>
<head>
<title>Left Justified: Statistics</title>

<style type="text/css">
.active1
{
font:caption;
color:inactivecaptiontext;
background:inactivecaption;
border:1px outset;
padding:0 .25em 0 .25em;
}
.active2
{
font:caption;
color:captiontext;
background:activecaption;
border:1px outset;
padding:0 .25em 0 .25em;
}
</style>

<script type="text/javascript">

window.onload = function()
{
var divs = document.getElementsByTagName("DIV"),
n = divs.length,
i = -1,
at;
while(++i < n)
{
at = divs[i];
if(!at.attributes["hideme"])
continue;
at.style.display = "none";
}

}

var arr = [];
function syncClass(e, top)
{
var ele = (e.target ? e.target : e.srcElement),
ar0 = arr[0],
ar1 = arr[1],
ar2 = arr[2],
stl;
if(ele.nodeName != "A")
return false;
var ref = document.getElementsByTagName("A")[ele.hash.substr(1)];
if(top)
{
if(ar1)
ar1.className = "";
ref.className = "active2";
arr[1] = ref;
ar1 = arr[1];
if(ele != ar0)
{
if(ar0)
ar0.className = "";
ele.className = "active1";
arr[0] = ele;
ar0 = arr[0];
ele = ref;
if(ar2)
ar2.display = "none";
}
stl = ref.parentNode.parentNode.parentNode.style;
stl.display = "";
arr[2] = stl;
ref = document.getElementsByTagName("A")[ref.hash.substr(1)];
}
if(ele != ar1 && ele != ar0)
{
ar1.className = "";
ele.className = "active2";
arr[1] = ele;
}
stl = ref.parentNode.parentNode.style;
if(!arr[3])
arr[3] = stl;
arr[3].display = "none";
stl.display = "";
arr[3] = stl;
}
</script>

</head>
<body>
<ul onclick="syncClass(event, 1)">
<li><a href="#serstats">Server Stats</a></li>
<li><a href="#usertats">User Stats</a></li>
<li><a href="#refstats">Referrer Stats</a></li>
</ul>

<div hideme>
<ul onclick="syncClass(event, 0)">
<li><a name="serstats" href="#serstats1">Site Hits</a></li>
<li><a href="#serstats2">Hits this Week</a></li>
<li><a href="#serstats3">Resources</a></li>
</ul>
<div hideme>
<h3><a name="serstats1">Hits <span>Uniques</span></a></h3>
<div>serstats1 data...</div>
</div>

<div hideme>
<h3><a name="serstats2">Hits in the last week</a></h3>
<div>serstats2 data...</div>
</div>

<div hideme>
<h3><a name="serstats3">Resources <span>Hits</span></a></h3>
<div>serstats3 data...</div>
</div>
</div>

<div hideme>
<ul onclick="syncClass(event, 0)">
<li><a name="usertats" href="#usertats1">Platform</a></li>
<li><a href="#usertats2">Browser</a></li>
<li><a href="#usertats3">Language</a></li>
</ul>
<div hideme>
<h3><a name="usertats1">Platform <span>%</span></a></h3>
<div>usertats1 data...</div>
</div>

<div hideme>
<h3><a name="usertats2">Browser <span>%</span></a></h3>
<div>usertats2 data...</div>
</div>

<div hideme>
<h3><a name="usertats3">Languages <span>%</span></a></h3>
<div>usertats3 data...</div>
</div>
</div>

<div hideme>
<ul onclick="syncClass(event, 0)">
<li><a name="refstats" href="#refstats1">Recent Referrers</a></li>
<li><a href="#refstats2">Repeat Referrers</a></li>
<li><a href="#refstats3">Search Strings</a></li>
</ul>
<div hideme>
<h3><a name="refstats1">Recent Referrers <span>When</span></a></h3>
<div>refstats1 data...</div>
</div>

<div hideme>
<h3><a name="refstats2">Repeat Referrers <span>Hits</span></a></h3>
<div>refstats2 data...</div>
</div>

<div hideme>
<h3><a name="refstats3">Search Strings <span>Hits</span></a></h3>
<div>refstats3 data...</div>
</div>
</div>
</body>
</html>

mindlessLemming
08-11-2004, 10:16 AM
Thanks :D
Still doesn't do it though :(
Also, is it really nessecarry to use invalid code? (<a name=""> and <div hideme>)
I can't use a custom doctype as this is going to be an addon to an existing open source product...
I can totally understand if you just want to wipe your hands of this whole mess. I'm more trouble than I'm worth most of the time ;)

neofibril
08-11-2004, 10:33 AM
Still doesn't do it though :(
Well, what's wrong?
(note that I fixed some pasting errors, 5 minutes after I posted that one...)


Also, is it really nessecarry to use invalid code?
I didn't know that expando attributes were invalid, nor that there was a problem with giving anchors a name attribute... isn't that how they work?

The "hideme" expando can be replaced with a name attribute (with a slight change in the script)... if that's more valid.


I can't use a custom doctype as this is going to be an addon to an existing open source product...
open source product :confused:


I can totally understand if you just want to wipe your hands of this whole mess. I'm more trouble than I'm worth most of the time ;)
I just play with scripts (for fun :)); feel free to inform me of the correct markup with which to exploit. :p

mindlessLemming
08-11-2004, 11:41 AM
Well, what's wrong?

Well, your div's get displayed just fine, but when I put the real content in there it doesn't display any of it...


I didn't know that expando attributes were invalid, nor that there was a problem with giving anchors a name attribute... isn't that how they work?

Oops, my mistake. I'm so used to coding in XHTML Strict, which only allows the name attribute on form elements. This is XHTML Trans, so <a name=""> is fine.
Expando? Never heard of it, but it sure ain't XHTML! :eek:


The "hideme" expando can be replaced with a name attribute (with a slight change in the script)... if that's more valid.

id="" is the only choice. If you have a look at my example in my original post, I have already assigned all the relevant ID's and marked up everything how it needs to be - including all show/hide functionallity.
All I really need is a function which walks through the <a> (or <li>) elements contained within a certain <ul> and assigns class="active" to one, while making sure that none of the others have class="active".


open source product :confused:

http://leftjustified.net/stats/
(Doesn't allow linking - copy paste url ;))

:D

neofibril
08-11-2004, 11:57 AM
The thing is, using an id for the divs changes the whole grouping dynamic: is 'name' invalid, or just not preferred for some reason?

Also, Is the "real content" (which doesn't show up) equal to that of your staticModule-demo-page, or no?
Another thing: the parentNode references are hard-coded, based on your example. If that needs to be flexible, I'd have to rethink it. :eek:

neofibril
08-11-2004, 01:31 PM
Ok, so 'name' was never valid for a div; sorry. :o

Would 'class' be problematic, as well?

OT:
the 'name' attrib being deprecated for anchors in XHTML strict: what's the alternative, I wonder?


@ If you want something done right... :D

Really, I assumed your markup was catering to the script, and when consolidating the two ideas into one event/function, it seemed better to change the references to that end.

Piecing together code snippets is usually not a great way to proceed, IMO.

mindlessLemming
08-12-2004, 01:21 AM
Would 'class' be problematic, as well?

Possibly, as the parent div's are already assigned classes...However, I would be willing to add an outer div around each one, if that's really nessecarry.


the 'name' attrib being deprecated for anchors in XHTML strict: what's the alternative, I wonder?

id's on any element.
eg:


<a href="#menu">Skip to Menu</a>
...
<ul id="menu">
<li>....




@ If you want something done right... :D

You're right :o
Thanks again for all your patient help - you've been a champ :thumbsup:
Maybe I should use this as an opportunity to start learning js... :eek:

neofibril
08-12-2004, 04:55 AM
Possibly, as the parent div's are already assigned classes...However, I would be willing to add an outer div around each one, if that's really nessecarry.
A regexp would facilitate distinction by class, but, after all, I guess its pretty lame to flag each div, just for one loop; so...

The following function does the same thing, minus the need for attributes -- except for the first <ul> having id="root":
<ul id="root" onclick="syncClass(event, 1)"> -- now, you can get rid of all that "hideme" nonsense :D

(This assumes that all of the <a> tags in that <ul>, and the ones they point to, have href="#...")
edit:// never fails (it doesn't work as I thought); i'll fix it...

alright... seems to work now (wasn't awake).

window.onload = function()
{
var anchs = document.getElementById("root").getElementsByTagName("A"),
atags = document.getElementsByTagName("A"),
ar = [],
n = anchs.length,
i = -1,
pn,
aa;
while(++i < n)
{
pn = atags[anchs[i].hash.substr(1)].parentNode.parentNode;
aa = pn.getElementsByTagName("A");
ar.push(aa.length, aa);
pn.parentNode.style.display = "none";
}
while(ar.length)
follow(-1, ar.shift(), ar.shift());
function follow(x, y, z)
{
while(++x < y)
atags[z[x].hash.substr(1)].parentNode.parentNode.style.display = "none";
}
}


id's on any element.
Ah, that's good to know; well if you'd rather use id's, the script works just fine with that (as do the anchors, strangely enough ;)); all that's really important is the position of each anchor being the same as what the function expects... including those wihin the <h3> tags! (If you want to change that, just play around with adding or removing the parentNode.parentNode... bits.)




Maybe I should use this as an opportunity to start learning js...
Surely you're as capable as I. :)

neofibril
08-12-2004, 01:46 PM
I'll have to leave it at that; something's come up...

mindlessLemming
08-13-2004, 03:42 PM
:D THanks for all your help.
I'll let you know how I go.



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum