Removing and event from the html code.

G

graham.reeds

I am updating a website that uses a countdown script embedded on the
page. When the page is served the var's are set to how long the
countdown has left in minutes and seconds, but the rest of the script
is left untouched.

However I want to take the script out of the page and have it as a
seperate file that can be cached, reducing serving costs - the page
gets hit a couple of thousand times per day, sometimes as high a 5K, so
any savings are multiplied.

The original script is:
----------
var min=40;
var sec=40;

function countdown()
{
if (sec==0 && min>0)
{ sec=59; min--; }
else
{ sec--; }

msg = '<b>Next Tick: ' + min + ':' + ((sec < 10) ? '0' : '') + sec +
'</b>';

if (document.all)
document.all.tel.innerHTML = msg;
else if (document.getElementById('tel'))
document.getElementById('tel').innerHTML = msg;

if (sec==0 && min==0)
{ min=60; sec=00; }
if (sec>0 || min>0)
setTimeout('countdown()',1000);
}
window.onload=countdown;
----------
Note: the var are set to 40 for testing purposes. In the actual script
they are set to the time that is left on the server.

So I thought the easiest way to do this would make the function accept
two vars, and then pass the parameters to the function from within the
html.

However the closest I can get is this:
----------
function countdown(m, s)
{
sec = s;
min = m;

if (sec==0 && min>0)
{ sec=59; min--; }
else
{ sec--; }

msg = '<b>Next Tick: ' + min + ':' + ((sec < 10) ? '0' : '') + sec +
'</b>';

if (document.all)
document.all.tel.innerHTML = msg;
else if (document.getElementById('tel'))
document.getElementById('tel').innerHTML = msg;

if (sec==0 && min==0)
{ min=60; sec=00; }
if (sec>0 || min>0)
setTimeout("countdown(min,sec)",1000);
}
window.onload=countdown(40,40);
----------
And this code only works in FF - it stops working in IE6. As soon as I
move the 'window.onload' line out of the .js file and into the HTML
code it stops working in FF too. I thought the code would be the
following, contained in <head>:
----------
<script src="scripts/countdown.js" type="text/javascript">
<!--
window.onload=countdown(40,40);
//-->
</script>
 
W

web.dev

I am updating a website that uses a countdown script embedded on the
page. When the page is served the var's are set to how long the
countdown has left in minutes and seconds, but the rest of the script
is left untouched.

However I want to take the script out of the page and have it as a
seperate file that can be cached, reducing serving costs - the page
gets hit a couple of thousand times per day, sometimes as high a 5K, so
any savings are multiplied.

The original script is:
----------
var min=40;
var sec=40;

function countdown()
{
if (sec==0 && min>0)
{ sec=59; min--; }
else
{ sec--; }

msg = '<b>Next Tick: ' + min + ':' + ((sec < 10) ? '0' : '') + sec +
'</b>';

if (document.all)
document.all.tel.innerHTML = msg;
else if (document.getElementById('tel'))
document.getElementById('tel').innerHTML = msg;

if (sec==0 && min==0)
{ min=60; sec=00; }

Are you sure this condition can be reached? Aside from setting your var
sec and min to zero. Also sec = 0; will suffice.
if (sec>0 || min>0)
setTimeout('countdown()',1000);
}
window.onload=countdown;

Your original script appears to be correct. However, you must also
realize how big your page is. If your page is really big (has a lot of
content), then when your countdown function is called after 1 second,
is the "tel" id available at that point?
----------
Note: the var are set to 40 for testing purposes. In the actual script
they are set to the time that is left on the server.

So I thought the easiest way to do this would make the function accept
two vars, and then pass the parameters to the function from within the
html.

However the closest I can get is this:
----------
function countdown(m, s)
{
sec = s;
min = m;

if (sec==0 && min>0)
{ sec=59; min--; }
else
{ sec--; }

msg = '<b>Next Tick: ' + min + ':' + ((sec < 10) ? '0' : '') + sec +
'</b>';

if (document.all)
document.all.tel.innerHTML = msg;
else if (document.getElementById('tel'))
document.getElementById('tel').innerHTML = msg;

if (sec==0 && min==0)
{ min=60; sec=00; }
if (sec>0 || min>0)
setTimeout("countdown(min,sec)",1000);
}
window.onload=countdown(40,40);

The problem here is also what I mentioned above. Plus, you now changed
your window.onload assignment to be that of the return value of
countdown, whereas in your original script, it was a reference to the
function.
----------
And this code only works in FF - it stops working in IE6. As soon as I
move the 'window.onload' line out of the .js file and into the HTML
code it stops working in FF too. I thought the code would be the
following, contained in <head>:
----------
<script src="scripts/countdown.js" type="text/javascript">
<!--
window.onload=countdown(40,40);
//-->
</script>
----------

Move the window.onload=countdown; back into your external js file and
use the original code.
 
G

graham.reeds

Are you sure this condition can be reached? Aside from setting your var
sec and min to zero. Also sec = 0; will suffice.

No sec=0 won't suffice. Just thinking about what the line does will
invalidate that statement. Just if sec > 0 won't suffice because at
the end of a minute sec will be equal to zero and the countdown will
stop.
However, you must also realize how big your page is. If your page is really
big (has a lot of content), then when your countdown function is called after
1 second, is the "tel" id available at that point?

That's why the window.onload event is used. The window.onload event is
triggered once the page has finished loading.
Move the window.onload=countdown; back into your external js file and
use the original code.

As I stated in my original post the site embedded the javascript into
the page and changed the two values when the page was generated. I
want to take the javascript out of the page to a seperate file but I
still need to be able to send the two values to the function. The 40,
40 values are just there so I can see if my changes break the code in
anyway.

G.
 
R

RobG

I am updating a website that uses a countdown script embedded on the
page. When the page is served the var's are set to how long the
countdown has left in minutes and seconds, but the rest of the script
is left untouched.

However I want to take the script out of the page and have it as a
seperate file that can be cached, reducing serving costs - the page
gets hit a couple of thousand times per day, sometimes as high a 5K, so
any savings are multiplied.
[...]

if (document.all)
document.all.tel.innerHTML = msg;
else if (document.getElementById('tel'))
document.getElementById('tel').innerHTML = msg;

That test would be more appropriately applied as:

if (document.getElementById) {
document.getElementById('tel').innerHTML = msg;
} else if (document.all){
document.all['tel'].innerHTML = msg;
}

since there are probably more browsers around that understand
getElementById than document.all.
if (sec==0 && min==0)
{ min=60; sec=00; }
if (sec>0 || min>0)
setTimeout('countdown()',1000);

setTimeout is not guaranteed to run at precisely the interval specified.

Depending on the accuracy you require (either for the whole interval or
for each tick), a better solution might be to get the local time, add
your offset, then do a countdown based on that. Run the count down at
about 200ms intervals so that you don't miss a 'tick' of the clock by
too much, or more frequently if you feel the need - but take account of
other scripts you may have running and what the overall workload on the
users PC will be.

}
window.onload=countdown;

There are no parenthesis here - window.onload is being passed a
reference to a function, which is the normal thing to do. Your new
window.onload is quite different (see below).


[...]
However the closest I can get is this:
----------
function countdown(m, s)
{
sec = s;
min = m;

That seems rather pointless, why not just use m & s throughout the rest
of the script, or use:

function countdown(min, sec)

if (sec==0 && min>0)
{ sec=59; min--; }
else
{ sec--; }

msg = '<b>Next Tick: ' + min + ':' + ((sec < 10) ? '0' : '') + sec +

Seconds are padded with a leading zero, why not the minutes too?


[...]
if (sec==0 && min==0)
{ min=60; sec=00; }

This ensures that your timer never expires (whether you use 00 or 0) -
it is re-set to 60 minutes when it runs down. Why do you think you need
00 rather than 0?

if (sec>0 || min>0)

if (sec || min)

will do.

setTimeout("countdown(min,sec)",1000);

If you want to pass reference to variables from this function to the next:

if (sec || min){
setTimeout(function(){
countdown(min, sec);
}, 1000);
}

}
window.onload=countdown(40,40);

Here you pass the result of the function to window.onload - it is
executed immediately, most likely before the rest of the page has loaded.

If you keep using global variables, then use the same statement as that
above. If you want to call the function with parameters, use:

window.onload = function() { countdown(40,40); }


And what error message do you get? Something like 'object expected' or
similar?
following, contained in <head>:

Don't use HTML comment delimiters inside script tags, it can have
unwanted side-effects and serves no useful purpose.

window.onload=countdown(40,40);

This assigns the *result* of running countdown to window.onload. Since
it doesn't return anything, it isn't run onload. countdown is run
immediately, and I suspect it works sometimes when in a .js file because
the file loads slowly enough that by the time it is executed, the 'tel'
element exists. If it doesn't, the script errors.
//-->
</script>

The entire following script can be placed in an external file. If you
want to use global variables in the HTML file, put them in the HTML
inside a script element and use them:


<script type="text/javascript">

function countDown(t, el)
{
var tLeft = t - new Date().getTime();
var mLeft = Math.floor(tLeft/60000);
var sLeft = Math.floor((tLeft%60000)/1000);

mLeft = (mLeft<10)? '0'+mLeft : mLeft;
sLeft = (sLeft<10)? '0'+sLeft : sLeft;
el.firstChild.data = mLeft + ':' + sLeft;

if (tLeft > 1000) {
setTimeout( function() {
countDown(t, el);
}, 200);
}
}

function startCountDown(min, sec)
{
if (!document.getElementById || !document.createTextNode) return;
var stopMSec = new Date().getTime() + (min*60 + sec)*1000 - 1;
var el = document.getElementById('xx'):

if (!el.firstChild) {
el.appendChild(document.createTextNode(' '));
}

countDown(stopMSec, el);
}

window.onload = function() {startCountDown(10,10);}

</script>

<div id="xx" style="font-weight: bold;">&nbsp;</div>
 
T

Thomas 'PointedEars' Lahn

RobG said:
I am updating a website that uses a countdown script embedded on the
page. When the page is served the var's are set to how long the
countdown has left in minutes and seconds, but the rest of the script
is left untouched. [...]

if (document.all)
document.all.tel.innerHTML = msg;
else if (document.getElementById('tel'))
document.getElementById('tel').innerHTML = msg;

That test would be more appropriately applied as:

if (document.getElementById) {
document.getElementById('tel').innerHTML = msg;
} else if (document.all){
document.all['tel'].innerHTML = msg;
}

since there are probably more browsers around that understand
getElementById than document.all.

Where neither the existence of a document.getElementById property
ensures it is a method that can be called, that it returns a useful
value when called, nor support for Document::getElementById() from
W3C DOM Level 1+ Core implemented as document.getElementById() or
the support for `document.all' from the MS DHTML Object Model implies
support for it and the proprietary `innerHTML' property. Therefore:

function isMethod(m)
{
if (typeof m == "string")
{
m = eval(m);
}

var t;
return m && ((t = typeof m) == "function) || t == "object");
}

var o;
if ((isMethod("document.getElementById")
&& (o = document.getElementById('tel')))
|| (typeof document.all != "undefined"
&& (o = document.all['tel'])))
{
if (typeof o.textContent != "undefined") // DOM Level 3 Core
{
o.textContent = msg;
}
else if (typeof o.innerHTML != "undefined") // DOM Level 0 proprietary
{
o.innerHTML = msg;
}
else if (typeof o.innerText != "undefined") // MS DHTML proprietary
{
o.innerText = msg;
}
}


PointedEars
 
T

Thomas 'PointedEars' Lahn

Thomas said:
function isMethod(m)
{
if (typeof m == "string")
{
m = eval(m);
}

var t;
return m && ((t = typeof m) == "function) || t == "object");
}
^
There's a " missing, of course ---------------'
 
G

grahamr

That test would be more appropriately applied as:
if (document.getElementById) {
document.getElementById('tel').innerHTML = msg;
} else if (document.all){
document.all['tel'].innerHTML = msg;
}

I know. I've since learnt that the document.all is for IE4 (and
possibly below) so it's been dropped. Also I've optimised the function
a bit further and got rid of a couple of extra lines.
setTimeout is not guaranteed to run at precisely the interval specified.

I'm not too concerned about the granularity of the time period. With
the time specified when the page is generated and the time it takes to
download and render the page (at least 2 seconds with IE) the time will
be out by a few seconds anyway. Besides it is simply there as a
guideline.
That seems rather pointless, why not just use m & s throughout the rest
of the script, or use:

Well I've been looking around the net for an answer: I'm not too good
at JS - I'm a C++ programmer by trade and an example of passing
parameters back to a function used that method.
Seconds are padded with a leading zero, why not the minutes too?

Haven't the foggiest. I never wrote the original code. Doesn't seem
necessary. In fact changing it so it does have a leading zero in front
of the minute looks weird.
This ensures that your timer never expires (whether you use 00 or 0) -
it is re-set to 60 minutes when it runs down. Why do you think you need
00 rather than 0?

Like I said earlier I inherited this script with the page. That
section has been subsequently rewritten and one of the tests removed.
Here you pass the result of the function to window.onload - it is
executed immediately, most likely before the rest of the page has loaded.

No. window.onload will only executed once the page has been fully
loaded. Not before.
And what error message do you get? Something like 'object expected' or
similar?

Actually I don't get an error message, but nothing is rendered.
Putting an alert as the first line of the function doesn't generate an
alert. JS Console in FF doesn't register anything either.
Don't use HTML comment delimiters inside script tags, it can have
unwanted side-effects and serves no useful purpose.

That is absolutely wrong. You can't validate your code without them.
This assigns the *result* of running countdown to window.onload. Since
it doesn't return anything, it isn't run onload. countdown is run
immediately, and I suspect it works sometimes when in a .js file because
the file loads slowly enough that by the time it is executed, the 'tel'
element exists. If it doesn't, the script errors.

window.onload won't execute until the page has fully loaded.

My original question was how do I call a function with window.onload
with two parameters.

Using the local system time won't work. The tick can be run at
anytime. Currently it is hourly (set to server time which is a minute
off) but what if the tick was decided to be run half hourly or even
shorter?

Thanks, Graham Reeds
 
G

grahamr

What on earth are you smoking?

That has nothing to do with my original question.

Thanks (maybe), Graham Reeds.
 
T

Thomas 'PointedEars' Lahn

grahamr said:
What on earth are you smoking?

I could ask you the same as you do not follow the
most basic rules of conduct for this newsgroup;
probably because you do not even know it is one.

That has nothing to do with my original question.

So? This is not an 1:1 medium and it is not
a support group. People are free to discuss.


PointedEars
 
V

VK

----------
<script src="scripts/countdown.js" type="text/javascript">
<!--
window.onload=countdown(40,40);
//-->
</script>

Unfortunately it cannot work like this. It's elegant and it follows to
the common logic (otherwise would not be repeated over and over by
different users) so it points to the serious script specs flaws I'm
going to list, rather than to algorithm problems.

1. <script> tag doesn't allow to combine external and inline code. So
in case like:

<script src="myScript.js" type="text/javascript">
<!--
// myInlineCode
//-->
</script>

only myScript.js will be loaded and executed.
myInlineCode block will be silently ignored

If you need to combine external and inline code, so far (?) you have to
use separate tag pairs:

<script src="myScript.js" type="text/javascript"></script>
<script type="text/javascript">
<!--
// myInlineCode
//-->
</script>

2. Programmatically assigned callbacks can be only function references.

So despite in intrinsic event hanlers you can use function calls with
args:
a) <body onload="myFunction(arg1, arg2)">
in programmed callbacks you are limited to:
window.onload = myFunction; // function reference

The regular way around in JavaScript is by using wrappers from
anonymous functions (called here "closures"):
b) window.onload = function() {myFunction(arg1,arg2);}
Rather ugly but you're forced to work with what you have. Actually
option a) is just a legacy endorsed variant of b) because internally it
looks like
<body onload="
function anonymous() {
myFunction(arg1, arg2);
}">

Not going further into details: if you rewrite the block as:

<script src="scripts/countdown.js" type="text/javascript"></script>
<script type="text/javascript">
var glbHours = 40; // server parsed
var glbMinutes = 40; // server parsed
</script>

and countdown.js contains:
....
function countdown() {
// use glbHours
// and glbMinutes
}
window.onload = countdown;
....

it will make it work. Again: personally I think that's just plain
stupid to have it as such, but what we have - we have to deal with (and
vice versa).
 
R

RobG

grahamr said:
That test would be more appropriately applied as:

if (document.getElementById) {
document.getElementById('tel').innerHTML = msg;
} else if (document.all){
document.all['tel'].innerHTML = msg;
}


I know. I've since learnt that the document.all is for IE4 (and
possibly below) so it's been dropped. Also I've optimised the function

document.all is still supported by IE (and probably will be for a very
long time) and has varying level of support from some other browsers.
It is a proprietary Microsoft method with no public standard, whereas
getElementById is open, backed by the W3C and supported by nearly all
modern browsers that have any sort of support for a DOM.


[...]
I'm not too concerned about the granularity of the time period. With
the time specified when the page is generated and the time it takes to
download and render the page (at least 2 seconds with IE) the time will
be out by a few seconds anyway. Besides it is simply there as a
guideline.

Fair enough.

[...]
Haven't the foggiest. I never wrote the original code. Doesn't seem
necessary. In fact changing it so it does have a leading zero in front
of the minute looks weird.

You may want to pad with a non-breaking space then, the minutes will
'jump' one character to the left when moving from 10 to 9 - it's up to
you of course. I like the zero padding... maybe others don't ;-)

[...]
No. window.onload will only executed once the page has been fully
loaded. Not before.

Re-read my comments below - you are passing the *result* of the
function, not a reference to it, which is the opposite of what you need
to do. See below.

[...]
That is absolutely wrong. You can't validate your code without them.

HTML comments? Try putting them after the first line of script, or in
an XHMTL document - search the newsgroup archives.

window.onload won't execute until the page has fully loaded.

Correct, but what is it running? You want to pass a reference to the
function so that window.onload has something to do when the page loads.
What you are doing is executing the function and passing the result to
window.onload, so the function is executed immediately.

window.onload = someFunction;

No parenthesis, so a reference passed. However:

window.onload = someFunction();

With parenthesis meas 'someFunction()' is executed immediately and the
result given to window.onload. the countdown() function has no return
value, window.onload has nothing to run.

My original question was how do I call a function with window.onload
with two parameters.


That advice was provided, explicitly.
Using the local system time won't work. The tick can be run at
anytime. Currently it is hourly (set to server time which is a minute
off) but what if the tick was decided to be run half hourly or even
shorter?

The code I gave you works, it also provides examples of passing
parameters to setTimeout and from window.onload.

You can use whatever method you like to count down, yours or mine, and
can change the length of time or interval by changing parameters. The
second argument to setTimeout can also be a variable if you want to
control how often it runs.
 
T

Thomas 'PointedEars' Lahn

grahamr wrote:

Please provide proper attribution. said:
That is absolutely wrong.

No, it is not. There is not one widely used and standards compliant user
agent that needs it (i.e. that does not understand the `script' element
introduced by 1997's HTML 3.2 Specification), and it can be a syntax error
with script engines that do not support this proprietary feature because
`<', `!' and `--' are operators.
You can't validate your code without them.

Rubbish. A decent markup validator, such as the W3C Markup Validator
at <http://validator.w3.org/>, "knows" (from the DTD referred to by the
DOCTYPE declaration on top of the document) that the `script' element's
content is CDATA in HTML. Therefore it does not parse it and it ignores
any strings you (and a browser) might consider comment delimiters.

Using it in XHTML is of course potentially harmful, as explained not only
here many times. However, a decent markup validator "knows" that XHTML's
`script' element's content is PCDATA that has to validated if not declared
otherwise. Buggy validators aside, which the W3C Markup Validator is not
in this regard, this, and only this, is the reason why one cannot validate
certain markup (containing unescaped `<' and `&', for example) without
comments strings which are real comments in XHTML's `script' element PCDATA
content. It was _your_ error in the first place, you should have declared
it to be CDATA or escaped markup delimiters then.

Then again, XHTML is not supported by IE; it is merely subject to error
correction if served, often improperly, as text/html; since there are
certain non-obvious incompatibilities between HTML and XHTML markup, the
latter should always be served as application/xhtml+xml which e.g. the
XML parser of Gecko-based user agents like Firefox is happy to accept
while IE is not at all. Which is a good reason to not use XHTML at all
if not forced by the usage of embedded XML-based markup languages like
SVG, CML or MathML, and to stick to HTML 4.01 (Strict) instead.

As already mentioned, all of this has been explained before, yet IIRC
not this compact. Therefore, hopefully this article will serve as a
reference in case of repeated questions regarding the subject.


PointedEars
 
R

RobG

RobG said:
grahamr wrote: [...]
My original question was how do I call a function with window.onload
with two parameters.

Call me soft...

Put this in a script file called 'countdown.js':

function countDown(el, min, sec)
{
--sec < 0 && min-- && (sec=59);

// If timer should start again if at 00:00
min < 0 && (min=59) && (sec=59);

// Or if timer should end at 00:00, replace above line with:
// if (min < 0) return;

if (sec < 10) sec = '0' + sec;
if (min < 10) min = '\u00A0' + +min;
el.firstChild.data = min + ':' + sec;

setTimeout(function(){countDown(el, min, sec);}, 1000);
}

function startCountDown(id, min, sec)
{
if (!document.getElementById || !document.createTextNode) return;
var el = document.getElementById(id);

// Add a text node to the 'clock' else browser may barf
if (!el.firstChild) {
el.appendChild(document.createTextNode(' '));
}
countDown(el, min, sec);
}


Put this in an HTML file:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Countdownr</title>
<script type="text/javascript" src="countdown.js"></script>
<script type="text/javascript">

window.onload = function() { startCountDown('theClock',10,5); }

</script>
</head><body>

<!-- Don't put any content in 'theClock' element -->
<div><pre id="theClock"></pre></div>

</body></html>
 
D

Dr John Stockton

JRS: In article <[email protected]>, dated Fri, 4
Nov 2005 01:16:37, seen in RobG
function countDown(el, min, sec)
{
--sec < 0 && min-- && (sec=59);

// If timer should start again if at 00:00
min < 0 && (min=59) && (sec=59);

// Or if timer should end at 00:00, replace above line with:
// if (min < 0) return;

if (sec < 10) sec = '0' + sec;
if (min < 10) min = '\u00A0' + +min;
el.firstChild.data = min + ':' + sec;

setTimeout(function(){countDown(el, min, sec);}, 1000);
}


I don't expect that setTimeout to count true seconds; not always, maybe
never : <URL:http://www.merlyn.demon.co.uk/js-date0.htm#TaI>. Put
DynWrite(anID, +new Date()) in the loop and observe the last three
digits in various systems.
Using setTimeout(..., 1010 - new Date()%1000) could fix that.

If any of the timed events is missed, the countdown will be discrepant.
I'd recalculate the time-to-go each time, from new Date() and a known
finish time.

But then there's the question of what happens if the machine time is
corrected during the process. The latter way will end at the right
time, the former after the right overall interval.
 
G

grahamr

Sorry, maybe I was a little harsh in my criticism, but your response to
my problem was a little tenuous to say the least.

G.
 
T

Thomas 'PointedEars' Lahn

grahamr said:
Sorry, maybe I was a little harsh in my criticism, but your response to
my problem was a little tenuous to say the least.

There we are again. It did not respond to your problem at all, and I
did not intend to (at least not with my first posting). Instead, I made
a technical comment to a solution provided by someone else. That's what
discussion is about and that is what is the difference between (this)
newsgroup and a support forum. Either get used to it or address another
audience (and medium). But stop complaining.


HTH

PointedEars
 
G

grahamr

Thank you! The code:
<script type="text/javascript" src="countdown.js"></script>
<script type="text/javascript">
window.onload = function() { startCountDown('theClock',10,5); }
</script>

was exactly what I needed to know.

Thanks for your help RobG.

G.
 

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,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top