Colour-by-ULR dropdown menu modifier

M

michael

How may the following script be modified to function with the list
structure below it?
In short: it is meant to apply a background style to groups of LI's and ULs
depeding on the URL filename.

<style>
..high {background-color: #99FFCC;}
..low {background-color: #33CC00;}
</style>

<script type="text/javascript">

function doClass(){
var As, ff, x;
var a = RegExp('.*/'); // Needed many times, compile for speed
var f = document.URL.replace(a,''); // filename of current page
var d = document.getElementById('menu');
var uls = d.getElementsByTagName('ul');

for (var i=0, j=uls.length; i<j; i++){
x = uls;

// If the UL className string includes word 'head'
if ( /\bhead\b/.test(x.className) ){
/* PS: my newsreader may remove forward slashes in the above regex */

// Get its A elements
As = x.getElementsByTagName('a');

// Search for matching file names
for (var k=0, m=As.length; k<m; k++) {
ff = As[k].href.replace(a,'');

// If match, modify the className string of the parent UL
if ( ff == f ){
x.className = x.className.replace(/\blow\b/,'high');

// No need to continue once we've found one
return;
}
}
}
}
}
</script>

<body onload="doClass()">

<ul id="menu">

<li><a href="z0.html">Flora&nbsp;&amp;&nbsp;puna</a>
<ul>
<li><a href="z1.html">Pretty&nbsp;flowers</a></li>
<li><a href="z2.html">Deadly&nbsp;vines</a></li>
</ul>
</li>

<li><a href="z3.html">Aquatic&nbsp;creatures</a>
<ul class="sub">
<li><a href="z4.html">Pretty&nbsp;fish</a></li>
<li><a href="z5.html">Don&#39t&nbsp;eat</a></li>
</ul>
</li>

</ul>

--
The script however was made to work with a different kind of list
structure, as below:

<div id="menu">
<ul class="head low">
<li><a href="z0.html">Flora&nbsp;&amp;&nbsp;puna</a>
<ul class="sub">
<li><a href="z1.html">Pretty&nbsp;flowers</a></li>
<li><a href="z2.html">Deadly&nbsp;vines</a></li>
</ul>
</li>
</ul>

<ul class="head low">
<li><a href="z3.html">Aquatic&nbsp;creatures</a></li>
<ul class="sub">
<li><a href="z4.html">Pretty&nbsp;fish</a></li>
<li><a href="z5.html">Don&#39t&nbsp;eat</a></li>
</ul>
</li>
</ul>
</div>

Although the above works in terms of colorising basic ULs, the structure
itself is not, as far as I know, compatible with further style methods that
would later make the hover dropdown menu, as below:

#menu, #menu ul {
padding: 0;
margin: 0;
list-style: none;
}

#menu a {
display: block;
width: 10em;
}

#menu li {
float: left;
width: 10em;
}
#menu li ul {
position: absolute;
width: 10em;
left: -999em;
}

#menu li:hover ul {
left: auto;
}

As such, could the Javascript be modified to work with the list structure
that work with these above style methods? So .high or .low styles would
still take affect for all LI's in each UL group where the filename is
matched, plus the one LI directly above each relevant UL group, which would
become the always visible headings of the complete CSS drop menu.

Thanks,
Michael
 
R

RobG

michael said:
How may the following script be modified to function with the list
structure below it?
In short: it is meant to apply a background style to groups of LI's and ULs
depeding on the URL filename.

The issue you are having is not with JavaScript. The script works as
designed, that is, it applies a class depending on whether the current
URL matches one in the menu or it's descendant.

However, if you define style tags the way you are on the UL elements,
classes have no effect.

The fix is to put the class on the LIs themselves, which can be done
using one of the following options:

1. Add the 'low' class to all the descendant LI elements in the HTML
source and change the script as per 'Option 1' below.

2. Don't add any classes in the HTML source, just add the 'high' class
to the LIs using the script as per 'Option 2' below.

3. Change the style of your default LIs to include the 'low' style
attributes you want, then use the script to change the attributes of
the LIs as required. (e.g. change the background color of the LI
elements directly as per 'Option 3' below.
<style>
.high {background-color: #99FFCC;}
.low {background-color: #33CC00;}
</style>

<script type="text/javascript">

function doClass(){
var As, ff, x;
var a = RegExp('.*/'); // Needed many times, compile for speed
var f = document.URL.replace(a,''); // filename of current page
var d = document.getElementById('menu');
var uls = d.getElementsByTagName('ul');

for (var i=0, j=uls.length; i<j; i++){
x = uls;

// If the UL className string includes word 'head'
if ( /\bhead\b/.test(x.className) ){
/* PS: my newsreader may remove forward slashes in the above regex */

// Get its A elements
As = x.getElementsByTagName('a');

// Search for matching file names
for (var k=0, m=As.length; k<m; k++) {
ff = As[k].href.replace(a,'');


Start of if block to replace:
// If match, modify the className string of the parent UL
if ( ff == f ){
x.className = x.className.replace(/\blow\b/,'high');

// No need to continue once we've found one
return;
}

/********** Option 1 **********/

Add the 'low' class to all 'LI elements and replace the above if block
with:

if ( ff == f ){
var lis = x.getElementsByTagName('LI');
for (var m=0, n=lis.length; m<n; m++){
lis[m].className = lis[m].className.replace(/\blow\b/,'high');
}

// No need to continue once we've found one
return;
}

/********** Option 2 **********/

Don't add any classes to your LI elements and replace the above if
block with:

if ( ff == f ){
var lis = x.getElementsByTagName('LI');
for (var m=0, n=lis.length; m<n; m++){
lis[m].className = 'high';
}

// No need to continue once we've found one
return;
}

/********** Option 3 **********/

Modify the style rule for your LI's:

#menu li {
float: left;
width: 10em; background-color: #33CC00;
}


Then change the backgroundColor of the LI's using the script. Replace
the above if block with:

if ( ff == f ){
var lis = x.getElementsByTagName('LI');
for (var m=0, n=lis.length; m<n; m++){
lis[m].style.backgroundColor = '#99FFCC';
}

// No need to continue once we've found one
return;
}

}
}
}
}
</script>

[...]

<ul class="head low">
<li><a href="z3.html">Aquatic&nbsp;creatures</a></li>

Terminating the above <li> element means the following ul is not a
child but a sibling, hence your CSS does not work for it (maybe just an
error from copying to/from your newsreader).
<ul class="sub">
<li><a href="z4.html">Pretty&nbsp;fish</a></li>
<li><a href="z5.html">Don&#39t&nbsp;eat</a></li>
</ul>
</li>
</ul>
</div>
[...]

Go crazy.
 
M

michael

Go crazy.

I already have... and I realised my style calls where all mucked up!

I just tested your 3 options, I can't say which is the better option to
use, although I'm sure they all work fine. But I could however not get any
of them to work. My backgrounds become and remain either #33CC00 or #99FFCC.

My last try with Option 3 has been included below together with the CSS
that make it a dropmenu.
(Note: This excludes a IE compatibility fix to bring the lists back into
page view.)

I'm a bit lost as to where class="head low" would now go?

I'd greatly appreciate it if you could kindly check and correct my errors
below and post back the complete HTML/JS/CSS code.

Many thanks,
Michael

<style type="text/css">
..high {background-color: #99FFCC; color: black;}
..low {background-color: #33CC00; color: white;}

/* remove bullets, margin's and padding */
#menu, #menu ul {
padding: 0;
margin: 0;
list-style: none;
}

/* expand link area */
#menu a {
display: block;
width: 10em;
}

/* float each li left */
#menu li {
float: left;
width: 10em; background-color: #33CC00;

}

/* move ul's within li's out of sight */
#menu li ul {
position: absolute;
width: 10em;
left: -999;
}

/* bring them back in */
#menu li:hover ul {
left: auto;
}

</style>

<script type="text/javascript">

function doClass(){
var As, ff, x;
var a = RegExp('.*/'); // Needed many times, compile for speed
var f = document.URL.replace(a,''); // filename of current page
var d = document.getElementById('menu');
var uls = d.getElementsByTagName('ul');

for (var i=0, j=uls.length; i<j; i++){
x = uls;

// If the UL className string includes word 'head'
if ( /\bhead\b/.test(x.className) ){
/* PS: my newsreader may remove forward slashes in the above regex */

// Get its A elements
As = x.getElementsByTagName('a');

// Search for matching file names
for (var k=0, m=As.length; k<m; k++) {
ff = As[k].href.replace(a,'');

// If match, modify the className string of the parent UL
if ( ff == f ){
var lis = x.getElementsByTagName('LI');
for (var m=0, n=lis.length; m<n; m++){
lis[m].style.backgroundColor = '#99FFCC'
}

// No need to continue once we've found one
return;
}
}
}
}
}
</script>

<body onload="doClass()">

<ul id="menu">

<li><a href="z0.html">Flora&nbsp;&amp;&nbsp;puna</a>
<ul>
<li><a href="z1.html">Pretty&nbsp;flowers</a></li>
<li><a href="z2.html">Deadly&nbsp;vines</a></li>
</ul>
</li>

<li><a href="z3.html">Aquatic&nbsp;creatures</a>
<ul class="sub">
<li><a href="z4.html">Pretty&nbsp;fish</a></li>
<li><a href="z5.html">Don&#39t&nbsp;eat</a></li>
</ul>
</li>

</ul>
 
R

RobG

michael said:
I already have... and I realised my style calls where all mucked up!

It was a suggestion, not a command! :)
I just tested your 3 options, I can't say which is the better option to
use, although I'm sure they all work fine. But I could however not get any
of them to work. My backgrounds become and remain either #33CC00 or #99FFCC.

Whatever background color you give the - #menu li - rule is the
background that the li elements will have by default.

When setting background color, you should always set the color
attribute/property too.
My last try with Option 3 has been included below together with the CSS
that make it a dropmenu.
(Note: This excludes a IE compatibility fix to bring the lists back into
page view.)

Option 3 is probably my pick too, it just means that the highlight
colour is in a script rather than a style rule, but I guess that's OK.
I'm a bit lost as to where class="head low" would now go?

The 'head' class is just so the script can find the 'ul' elements that
are children of the encompassing menu 'div'. I've changed that so it
now uses your 'ul' element and its childNodes, you no longer need
either class.

Take care and test thoroughly, from memory some browsers have poor
support for the childNodes collection.
I'd greatly appreciate it if you could kindly check and correct my errors
below and post back the complete HTML/JS/CSS code.

The CSS/HTML you have posted works OK in Firefox, but not IE - the
menus don't 'drop down' so I can't fully test it. As far as I can
tell, once you fix the CSS for IE it should be OK.

I've modified the script and put it in an external file, here's the
full working version based on your CSS & HTML.

I also added a fix for IE to allow for backslashes in file paths, I
think it only does that on local files.

The id of the 'menu' ul is now passed by the onload call, that way it's
not buried in a script.


/********** JavaScript file (I called it 'doclass.js' **************/

function doClass(c){

var As, ff, x;
var a = RegExp('.*[/\\\\]'); // Allow for '/' & '\'
var f = document.URL.replace(a,''); // Filename of current page
var hc = '#CC99FF'; // Highlight colour

if (document.getElementById) {
var lisA = document.getElementById(c).childNodes;
} else if (document.all) {
var lisA = document.all[c].childNodes;
} else {

// Bail if neither getElementById or document.all supported
return;
}

for (var i=0, j=lisA.length; i<j; i++){
x = lisA;

// Only play with 'li' and check style supported
if ('LI' == x.nodeName && x.style ) {
// Get its A elements
As = x.getElementsByTagName('a');

// Search for matching file names
for (var k=0, m=As.length; k<m; k++) {
ff = As[k].href.replace(a,'');

// If match, modify the background of all the LI's
// grandparent LI
if ( ff == f ){
x.style.backgroundColor = hc;
var lisB = x.getElementsByTagName('LI');
for (var m=0, n=lisB.length; m<n; m++){
lisB[m].style.backgroundColor = hc;
}
// No need to continue once we've found the match
return;
}
}
}
}
}

/********** HTML file (I called it 'z0.html' **************/

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<title>z0</title>
<meta http-equiv="Content-Type"
content="text/html; charset=ISO-8859-1">
<style type="text/css">

/* remove bullets, margin's and padding */
#menu, #menu ul {
padding: 0;
margin: 0;
list-style: none;
}

/* expand link area */
#menu a {
display: block;
width: 10em;
}

/* float each li left */
#menu li {
float: left;
width: 10em;

/* NOTE: always set color when setting background color */
color: black; background-color: #D5DDEE;
}

/* move ul's within li's out of sight */
#menu li ul {
position: absolute;
width: 10em;

/* You forgot the units here */
left: -999em;
}

/* bring them back in */
#menu li:hover ul {
left: auto;
}

</style>

<script type="text/javascript" src="doclass.js"></script>

</head>
<body onload="doClass('menu')">
<ul id="menu">

<li><a href="z0.html">Flora&nbsp;&amp;&nbsp;puna</a>
<ul>
<li><a href="z1.html">Pretty&nbsp;flowers</a></li>
<li><a href="z2.html">Deadly&nbsp;vines</a></li>
</ul>
</li>

<li><a href="z3.html">Aquatic&nbsp;creatures</a>
<ul class="sub">
<li><a href="z4.html">Pretty&nbsp;fish</a></li>
<li><a href="z5.html">Don&#39t&nbsp;eat</a></li>
</ul>
</li>

</ul>
</body>
</html>
 
M

michael

tell, once you fix the CSS for IE it should be OK.

That works very well. I added the Suckerfish IE fix from htmldog.com:

sfHover = function() {
var sfEls = document.getElementById("menu").getElementsByTagName("LI");
for (var i=0; i<sfEls.length; i++) {
sfEls.onmouseover=function() {
this.className+=" sfhover";
}
sfEls.onmouseout=function() {
this.className=this.className.replace(new RegExp(" sfhover\\b"), "");
}
}
}
if (window.attachEvent) window.attachEvent("onload", sfHover);

And the following style:

#menu li.sfhover ul {
left: auto;
}

Menus then function on Explorer 5. The doClass works fully everywhere I
tested too, including Opera 7.54 on Windows, Konqueror 3.4.0 on Linux, and
as Safari on OSX should be the same browser, I guess it works there too.

Many thanks,
Michael
 
T

Thomas 'PointedEars' Lahn

michael said:
How may the following script be modified to function with the list
structure below it?
In short: it is meant to apply a background style to groups of LI's and
ULs depeding on the URL filename.

<style>
.high {background-color: #99FFCC;}
.low {background-color: #33CC00;}
</style>

JFTR: It should be

<style type="text/css">
.high {background-color: #9fc;}
.low {background-color: #3c0;}
</style>

1. The `type' attribute is mandatory
2. Using hex triplets instead of hex sextets removes the
dependency on the color depth of the user's device.

Would your sender address not have been falsified, I might have taken
the time to look over the rest of your code instead of waiting for a
properly posted stripped-down test case.


PointedEars
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,902
Latest member
Elena68X5

Latest Threads

Top