Q: Automatically Changing Background Color of a Table Cell?

D

Dr John Stockton

JRS: In article <di3Bd.63892$QR1.37398@fed1read04>, dated Fri, 31 Dec
2004 03:01:31, seen in Arthur Shapiro
A general question: as you can tell, I'm a javascript novice (although a
software engineer with decades of experience). What sort of tools are
available for stepping through and otherwise debugging a small script such as
the one in question? That seems like a practical way to pick up this stuff.
Clearly it takes time and a lot of false steps to reach your obvious level of
proficiency.

With that experience, you may well recall punched cards and the daily
test run.

Firstly, be sure that in initial code development you are as far away
from that state as possible. No uploading, for example; just have a
browser and a backing-up editor open side-by-side on the same file, so
that you can edit-save-refresh within seconds.

Indeed, with a local copy (to save our bandwidth) of <URL:http://www.mer
lyn.demon.co.uk/js-quick.htm> one can just edit-test-edit for simple
code.

With a rapid test cycle, you can add only the minimum code at one time;
if you can test something after ten keystrokes, the number of possible
errors is greatly reduced. You can also use alert(X) freely, to verify
values; and comment it out or drag it away when not immediately wanted.

If the script uses a form, pre-load the input controls while testing by
using 'value="<default>"' and 'checked', so that the point at issue can
be re-tested without re-typing data.

You will have noticed that most script, here and on the Web, uses
excessive code repetition. ISTM that modularising into small functions
that can be tested independently, even if some are only called at one
location, is at least as useful in javascript as it is elsewhere.

Use validators frequently.

Others will no doubt write of tools outside editor-&-basic-browser.
However, it might have been well to say what browser(s) you have to
hand. Since so many things are, internationally, different from what
they may be in your unspecified country, it would be well to give your
approximate location; even if your code is intended to be international,
your habits may remain local.


Remember that all the code in a page is downloaded, perhaps over slow
dial-up. Therefore, eschew bloated functions with numerous options of
which any given page needs only one or two.


See the newsgroup FAQ & notes; and try my site.
 
A

Arthur Shapiro

With that experience, you may well recall punched cards and the daily
test run.
Yep! (not to mention paper tape).

At the risk of overextending my welcome, your very comprehensive response
about code development doesn't seem to address one concern that I suspect
isn't unique to my own situation: how does one address behavioral differences
among browsers? The previous discussion of my personal calendar script got
into this, where something simply didn't work in Foxfire although it worked
fine in IE. Ivo gave a different approach that worked, and I happily used it,
but I don't know how I would have attacked the problem myself.

I just tried to diddle the code so that the "empty" squares that round out the
start and the end of the month in my calendar table would be automatically
colored. I made the previously discussed code an "else" block, using the
following code for the "if" block:

if (td.innerText=="")
{ td.bgColor = '#c63800'; }

Works like a champ in IE, but once again it does absolutely zilch in Mozilla.
I just don't yet have a feel for the necessary technique / discipline in
dealing with an issue like this

Art
Temporary usercode - to be deleted when spam starts. Use MyBrainHurts at this ISP to reach me
 
R

Randy Webb

Arthur Shapiro wrote:

I just tried to diddle the code so that the "empty" squares that round out the
start and the end of the month in my calendar table would be automatically
colored. I made the previously discussed code an "else" block, using the
following code for the "if" block:

if (td.innerText=="")
{ td.bgColor = '#c63800'; }

Works like a champ in IE, but once again it does absolutely zilch in Mozilla.
I just don't yet have a feel for the necessary technique / discipline in
dealing with an issue like this


It works in IE but not Mozilla because .innerText is IE only code.

Start with your page in Mozilla, debug it there. Tools>Web
Development>Javascript Console. Once you have it working in Mozilla,
then and only then, test it in IE. You will soon find that it makes
debugging a lot simpler.
 
R

RobG

Arthur said:
OK, fair enough - as it had only been a couple of days I was working under the
assumption that it was a "current" topic.

I'll work under the assumption you are still reading this
thread...
Take a look at the minimal test case:

http://www.ocrebels.com/javascripttest.htm

This is one row of an html table-based calendar, with javascript courtesy of a
very helpful participant in this forum. The script is intended to change the
bgcolor of cells representing dates prior to today's date.

It does, in Internet Explorer.

It doesn't in Mozilla or Firefox. About the only obvious curiosity is that
the Mozilla javascript console reports "td has no properties" - which is
certainly true.

So the apparent question is: "is there something I need to know about
Javascript as implemented for Mozilla/Firefox, so I can achieve the same
functionality as seems to occur with IE?"

More like you need to learn the W3C DOM and the elements
interface. The problem with Microsoft is that they don't often
(ever?) tell you when they are extending the interface, so if you
just use their documentation and develop in IE, you will almost
certainly develop incompatible code.

Develop with Firefox/Mozilla/Netscape and test in IE and all the
others and you will have fewer issues to fix.

You could use the getElementsByTagName, but if you want a
"cleaner" fix, here's my suggestion:

Put your date cells into a tbody element. This is actually
required by the HTML spec, but because almost no one does it,
browsers insert it automatically where they think is appropriate.
So by using it, you are creating "better" HTML.

Now use getElementById on the tbody id, not the table id.
Incidentally, you should test for gEBI and add a method for
document.all if you think some of your visitors may be using an
old version IE (pre 5.5 I think).

Once you have the tbody, use the rows collection, then go through
the child nodes. Test for TDs and get the text from them and do
your stuff.

Lastly, 'bgcolor' is depreciated, use style="background-color: "
(since you are using style on the table anyway). The related DOM
attribute is accessed using 'camelCase' - style.backgroundColor.

Some sample code below. I have added a row and a thead to better
show how it all works. There are many other methods of getting
the cells and changing the contents, this way is OK but it is
unnecessarily dependent on the HTML structure of the cells (i.e.
that the cell firstChild is text and only a digit).

Another method is to dynamically create the calendar and set the
background color to the right value depending on the date
inserted into the cell when you create it. It takes fewer lines
of code overall but makes the page utterly dependent on
JavaScript. Of course, you could do it on the server and remove
client-side dependencies altogether.

Happy New Year! :)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><title>JavaScript Test Page</title>
<meta http-equiv="Content-Type" content="text/html;
charset=windows-1252">
</head>
<body>

<TABLE BORDER="5" WIDTH="100%"
style="FONT-FAMILY:Verdana; FONT-SIZE:10px;
background-color: #ffccc5;">
<thead>
<tr><td colspan="4">The header row</td></tr>
</thead>
<tbody id="calendar">
<TR ALIGN="LEFT" VALIGN="TOP">
<TD>0<br><BR>test</TD>
<TD>1<BR><BR>test</TD>
<TD>2<BR><br>test<BR></TD>
<TD>3<br><BR>test<BR></TD>
</tr><tr>
<TD>4<br><br>test<BR></TD>
<TD>5<BR><br>test<br></TD>
<TD>6<BR><br>test<br></TD>
<TD>&nbsp;</TD>
</TR>
</TABLE>

<script type="text/javascript">
var now = new Date().getDate(),
rows = document.getElementById('calendar').rows;
for (var i=0, rl=rows.length; i<rl; i++) {
var cells = rows.childNodes;
for (j=0, cl=cells.length; j<cl; j++) {
if (cells[j].nodeName == 'TD'
&& cells[j].firstChild.nodeValue != ''
&& cells[j].firstChild.nodeValue < now) {
cells[j].style.backgroundColor = '#c63800';
}
}
}
</script>
</html>
</body>
 
A

Arthur Shapiro

Thanks, both Randy and Rob. I'll be pondering your suggestions this evening,
not being much of a New Year celebrant. IE only, eh?! How was I supposed to
know that?

I think by the time I get this silly calendar behaving the way I want, I'll
know a lot more than when I started this thread.

The Java Console doesn't seem to do much for me but pop up an error once in a
while; am I missing something obvious that sets it as some sort of
trace/debugging engine?

Art






Art
Temporary usercode - to be deleted when spam starts. Use MyBrainHurts at this ISP to reach me
 
A

Arthur Shapiro

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><title>JavaScript Test Page</title>
<meta http-equiv="Content-Type" content="text/html;
charset=windows-1252">
</head>
<body>

<TABLE BORDER="5" WIDTH="100%"
style="FONT-FAMILY:Verdana; FONT-SIZE:10px;
background-color: #ffccc5;">
<thead>
<tr><td colspan="4">The header row</td></tr>
</thead>
<tbody id="calendar">
<TR ALIGN="LEFT" VALIGN="TOP">
<TD>0<br><BR>test</TD>
<TD>1<BR><BR>test</TD>
<TD>2<BR><br>test<BR></TD>
<TD>3<br><BR>test<BR></TD>
</tr><tr>
<TD>4<br><br>test<BR></TD>
<TD>5<BR><br>test<br></TD>
<TD>6<BR><br>test<br></TD>
<TD>&nbsp;</TD>
</TR>
</TABLE>

<script type="text/javascript">
var now = new Date().getDate(),
rows = document.getElementById('calendar').rows;
for (var i=0, rl=rows.length; i<rl; i++) {
var cells = rows.childNodes;
for (j=0, cl=cells.length; j<cl; j++) {
if (cells[j].nodeName == 'TD'
&& cells[j].firstChild.nodeValue != ''
&& cells[j].firstChild.nodeValue < now) {
cells[j].style.backgroundColor = '#c63800';
}
}
}
</script>
</html>
</body>

OK, I've spent some time looking at this example, which sure enough works in
both browsers.

My initial curiosity was why it correctly marked the "empty" cell with the
darker background color. Apparently the firstChild value for that cell of
"null" is numerically lower than the integer value of "now", and that makes
things work. Is that considered a "kosher" programming technique?

I then tried making the empty cell simply <td></td> and javascript failed on
an "object required" error. It's not a big deal to me to always have a space
or a <br> in the cell, but I'm curious what Javascript technique we might
typically use to isolate totally empty elements. That was why I had tried the
innerText construct before being told it was IE only.

Neglecting the reality that I'm trying to solve a real problem in the
organization's web site, this is all technically fascinating. I'm
appreciative of folks' patience.

Art
Temporary usercode - to be deleted when spam starts. Use MyBrainHurts at this ISP to reach me
 
R

RobG

Arthur Shapiro wrote:
[...]
My initial curiosity was why it correctly marked the "empty" cell with the
darker background color. Apparently the firstChild value for that cell of
"null" is numerically lower than the integer value of "now", and that makes
things work. Is that considered a "kosher" programming technique?

It's not "null", it's a non-breaking space, which conveniently
evaluates as less than 1 (today for me being 1 Jan 2005). If you
put nearly any other character in there, it will be bigger than 1
and hence get the default colour. Even more conveniently, the
non-breaking space makes the geko-based browsers display the
'empty' cell. A normal plain space is removed - I suggest you
download Firefox to see what I mean.
I then tried making the empty cell simply <td></td> and javascript failed on
an "object required" error.

Yes, because there is no firstChild for the <TD> node. That can
be overcome, but then as previously mentioned, geko browsers
won't show the (now totally) empty cell even though IE does.

Incidentally, I don't think the HTML spec says what to do with
empty cells, so neither IE or Geko is "correct" here, but I think
IE's approach is more logical.
It's not a big deal to me to always have a space
or a <br> in the cell, but I'm curious what Javascript technique we might
typically use to isolate totally empty elements. That was why I had tried the
innerText construct before being told it was IE only.

Go the other way. Set the default colour, evaluate the value of
the firstChild as an int, then change it if it's equal to or
larger than today. But make the default reasonable so that
browsers without JS or not enabled can still use the site.

e.g.
...
<TABLE BORDER="5" WIDTH="100%" style="FONT-FAMILY:Verdana;
FONT-SIZE:10px; background-color: #aaaaaa;">
...

if (cells[j].nodeName == 'TD'
&& cells[j].firstChild.nodeValue != ''
&& +cells[j].firstChild.nodeValue >= now) {
cells[j].style.backgroundColor = '#ddddee';
}
...

Now your empty cells can be totally empty and will be OK in IE
and the Geko browsers.

The background-color can be set on the tbody, not the table, if
you want. It is also generally frowned upon to set font sizes in
px, use % or similar then set other sizes (cell widths, etc.) to
'em' and all will scale if visitors are using bigger or smaller
base fonts.
Neglecting the reality that I'm trying to solve a real problem in the
organization's web site, this is all technically fascinating. I'm
appreciative of folks' patience.

Ah, but that's the allure of web development!
 
R

RobG

RobG wrote:
[...]
if (cells[j].nodeName == 'TD'
&& cells[j].firstChild.nodeValue != ''
&& +cells[j].firstChild.nodeValue >= now) {
cells[j].style.backgroundColor = '#ddddee';
}
...

Now your empty cells can be totally empty and will be OK in IE
and the Geko browsers.

Ooops, I fibbed. I copied the wrong code, use:

for (j=0, cl=cells.length; j<cl; j++) {
if (cells[j].nodeName == 'TD'
&& cells[j].firstChild
&& cells[j].firstChild.nodeValue != ''
&& +cells[j].firstChild.nodeValue >= now) {
cells[j].style.backgroundColor = '#ddddff';
}
}

There is an extra test to see if firstChild exists at all so it
won't error if it doesn't (totally empty cell).
 
D

Dr John Stockton

JRS: In article <j1mBd.67829$QR1.52379@fed1read04>, dated Sat, 1 Jan
2005 00:20:31, seen in Arthur Shapiro
Yep! (not to mention paper tape).

At the risk of overextending my welcome, your very comprehensive response
about code development doesn't seem to address one concern that I suspect
isn't unique to my own situation: how does one address behavioral differences
among browsers? The previous discussion of my personal calendar script got
into this, where something simply didn't work in Foxfire although it worked
fine in IE. Ivo gave a different approach that worked, and I happily used it,
but I don't know how I would have attacked the problem myself.


Well, the best answer is probably the trivial one of using only what you
know to work in "all" systems.


As far as I can see, there would be no problem in writing HTML to show
any one view of the calendar, as a Table; and that code would be fairly
repetitive.

FAQ 4.15 indicates how javascript can replace the contents of an
existing DIV (note : or other element), in any reasonable browser -
IIRC, that excludes mainly Netscape 4.

So you could compute the whole Table as a string to be rewritten to a
DIV every time the contents need to change - that uses more CPU cycles,
but plenty are available.

My <URL:http://www.merlyn.demon.co.uk/holidays.htm> works that way, and
AFAIK works in all browsers better than NS4 (RSVP if any US/CA, or
other, holidays are wrong).


Otherwise, when you find a feature that, as you have it, does not work
in some systems, see if you can isolate the use of that feature into a
single small parameterised function called whenever required, and then
generalise that function using feature detection (FAQ 4.26, FAQ Notes).

<FAQENTRY> 4.37 refers to "featuresting" </FAQENTRY>
 
A

Arthur Shapiro

Well, the best answer is probably the trivial one of using only what you
know to work in "all" systems.
At this point, I don't have enough experience to know what works in all
systems!
FAQ 4.15 indicates how javascript can replace the contents of an
existing DIV (note : or other element), in any reasonable browser -
IIRC, that excludes mainly Netscape 4.

Interesting. The site is known to not render at all in Netscape 4, due to the
Javascript that positions all the page elements, so that's not an issue.
So you could compute the whole Table as a string to be rewritten to a
DIV every time the contents need to change - that uses more CPU cycles,
but plenty are available.

I'm *very* happy with the way things look right now, and don't see the need to
create it "on the fly", but I'll study that area of the FAQ for potential
future use. I will soon make the change that Rob suggested yesterday - I was
rather stunned to see that one could use the construct "cells[j].firstChild"
as a Boolean to establish whether or not the object even exists, thus allowing
a totally empty cell rather than having to insert a <br> or nonbreaking space.
That just seemed intuivitevely non-obvious; I'd expect it (validity checking)
to be some sort of method.

Anyway, everyone's been of great help here, and the calendar works like a
champ. I even found a member with a Mac, who reported it functioned as
expected. If any of you are bicyclists, and are visiting southern
California, we'd be honored to have you ride with us; you can see the
nuclear calendar partway down the page at http://www.ocrebels.com/rides.htm.

Art
Temporary usercode - to be deleted when spam starts. Use MyBrainHurts at this ISP to reach me
 

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,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top