Script doesn't work in Safari

E

elektrophyte

I've got a short script that works fine in I.E. and Firefox, but not in
Safari. It is supposed to print a constantly-updating counter on the
webpage. Any ideas how to get it to work in Safari? The script uses the
Date object, especially Date.getTime(). Could that have something to do
with the problem?

Thanks,

E


// This <form> is put into the same HTML page as the script...
<form name="counter" style="margin: 0; padding: 0;">
<input type="text" name="amount" value="0" size="40" readonly="true"
style="margin:0;padding:0;border:none;font-size:24px;color:#cc0000;">
</form>

// Here is the script...
<script type="text/javascript">

// The formatNumber function comes from Danny Goodman's JavaScript
Cookbook.
[ ... some code left out here for brevity ... ]

var startingDate = new Date(2005, 0, 1);
var startingDebt = 1000000000;
function updateCounter(){
var nowDate = new Date();
var debtTimeInSeconds = (nowDate.getTime() -
startingDate.getTime())/1000;
var newValue = startingDebt + (debtTimeInSeconds * 3.47);
document.counter.amount.value = "$" + formatNumber(newValue, 2);
}
updateCounter();
intervalID = setInterval("updateCounter()", 1000);
</script>
 
R

RobG

elektrophyte said:
I've got a short script that works fine in I.E. and Firefox, but not in
Safari. It is supposed to print a constantly-updating counter on the
webpage. Any ideas how to get it to work in Safari? The script uses the
Date object, especially Date.getTime(). Could that have something to do
with the problem?

Thanks,

E


// This <form> is put into the same HTML page as the script...
<form name="counter" style="margin: 0; padding: 0;">
<input type="text" name="amount" value="0" size="40" readonly="true"
style="margin:0;padding:0;border:none;font-size:24px;color:#cc0000;">
</form>

// Here is the script...
<script type="text/javascript">

// The formatNumber function comes from Danny Goodman's JavaScript
Cookbook.
[ ... some code left out here for brevity ... ]

var startingDate = new Date(2005, 0, 1);
var startingDebt = 1000000000;
function updateCounter(){
var nowDate = new Date();
var debtTimeInSeconds = (nowDate.getTime() -
startingDate.getTime())/1000;

Manually wrap posted code at about 70 characters, allowing
auto-wrapping can cause problems and with space indents not tabs.

You also don't need the 'getTime()' method:

var debtTimeInSeconds = (nowDate - startingDate)/1000;

var newValue = startingDebt + (debtTimeInSeconds * 3.47);
document.counter.amount.value = "$" + formatNumber(newValue, 2);
}
updateCounter();
intervalID = setInterval("updateCounter()", 1000);
</script>

It works fine in Safari 1.0.3 as far as I can tell if you remove the
'formatNumber()' function. Post it for a fix.
 
R

RobG

RobG said:
elektrophyte wrote:
[...]

It works fine in Safari 1.0.3 as far as I can tell if you remove the
'formatNumber()' function. Post it for a fix.

A little more playing shows that the debit in cents seems to exceed the
size of integer that Safari can handle. I'll guess that the Danny
Goodman's function converts the amount to cents and uses Math.floor (or
round maybe) to truncate the decimal cents.

Here's a version of the script that uses a modified version of Dr J R
Stockton's 'TryCash()' function (which originally was based on cents
but I've modified it to use decimal currency). Lightly tested (Firefox
& Safari on OS X):


<script type="text/javascript">

var startingDate = new Date(2005,0,1);
var startingDebt = 1000000000;

function updateCounter(){
var nowDate = new Date();
var debtTimeInSeconds = (nowDate - startingDate)/1000;
var newValue = startingDebt + (debtTimeInSeconds * 3.47);
document.counter.amount.value = TryCash(newValue + ' $ , .');
}
updateCounter();
intervalID = setInterval("updateCounter()",1000);

function toCash(p, c, t, d) {
var s = (0 > p)? "-" : "";
p = p.split('.');
var m = String(Math.abs(p[0]));
var j, k = "", f;
c = c || "";
t = t || "";
d = d || ".";
while (m.length < 3) {
m = "0"+m;
}
f = (p[1])? twoDigits(p[1]) : '00';
j = m.length;
while (j > 3) {
k = t+m.substring(j-3, j)+k;
j -= 3;
}
k = m.substring(0, j)+k;
return s+c+k+d+f;
}

function TryCash(S) {
var T = S.split(/\s+/);
return toCash(T[0], T[1], T[2], T[3]);
}

function twoDigits(x){
return (x.length < 2)? x+'0' : x.substring(0,2);
}

</script>
 
D

Dr John Stockton

JRS: In article <428e9d89$0$956$5a62ac22@per-qv1-newsreader-
01.iinet.net.au>, dated Sat, 21 May 2005 12:31:32, seen in
news:comp.lang.javascript said:
RobG said:
elektrophyte wrote:
[...]

It works fine in Safari 1.0.3 as far as I can tell if you remove the
'formatNumber()' function. Post it for a fix.

A little more playing shows that the debit in cents seems to exceed the
size of integer that Safari can handle.
...

Which is?

Does Safari actually have a distinct integer type?

Is it just that Math.floor .ceil .round use Int32 internally (so that
they may have the mechanism for returning larger numbers, but never
generate them)?

AFAIR, according to spec, the only things that should be limited to
Int32 are the seven operators ~ & | ^ << >> >>> and their assignment
forms.

~~X appears to truncate X towards zero and do a signed modulo
2^32 on it. There must be a use for that.
 
E

elektrophyte

Thank you very much for the replies. As suggested I removed the
getTime() and formatNumber() calls and now it works in Safari. Now I
just need to debug formatNumber(). I got it from Danny Goodman's
JavaScript Cookbook (Oreilly). Maybe I'll just try to write my own
function to format the number. In case anyone is curious, I'll add
Goodman's code below.

// The formatNumber function comes from Danny Goodman's
// JavaScript Cookbook.
function formatNumber (num, decplaces) {
// convert in case it arrives as a string value
num = parseFloat(num);
// make sure it passes conversion
if (!isNaN(num)) {
// multiply value by 10 to the decplaces power;
// round the result to the nearest integer;
// convert the result to a string
var str = "" + Math.round (eval(num) *
Math.pow(10,decplaces));
// exponent means value is too big or small
// for this routine
if (str.indexOf("e") != -1) {
return "Out of Range";
}
// if needed for small values, pad zeros
// to the left of the number
while (str.length <= decplaces) {
str = "0" + str;
}
// calculate decimal point position
var decpoint = str.length - decplaces;
// assemble final result from: (a) the string
// up to the position of
// the decimal point; (b) the decimal point;
// and (c) the balance
// of the string. Return finished product.
return str.substring(0,decpoint) + "." +
str.substring(decpoint,str.length);
} else {
return "NaN";
}
}
 
R

RobG

elektrophyte said:
Thank you very much for the replies. As suggested I removed the
getTime() and formatNumber() calls and now it works in Safari. Now I
just need to debug formatNumber(). I got it from Danny Goodman's
JavaScript Cookbook (Oreilly). Maybe I'll just try to write my own
function to format the number. In case anyone is curious, I'll add
Goodman's code below.

Here's another that can handle any precision and adds commas. Remove
validation and comments and it's only marginally longer that DG's.


function formatDecimal(n, d) {
// Is n digit(s) with optional point or optional point and digit(s)
if ( !/^(\d+)[\.|(\.\d+)]*$/.test(n) ) {
return "Number part should be format 0 or 0.0";
}

// Is d an int?
if ( !/^(\d+)[\.|(\.0+)]*$/.test(d) ) {
return "Number of decimal places must be an integer";
}

// nd is number of digits before zero
var nd = (n + '').split('.')[0].length;

// len is total number of digits required
var len = +d + nd;

// n is array of digits with decimal place removed
n = n.replace(/\./,'').split('');

// If there is a digit after required length, do rounding,
var i=len, r='';

// If last+1 digit is bigger than 4
if ( n && n > 4 ){
// While preceding number is 9 and not first
while ( 9 == n[--i] && i > 0 ) {
// Make it zero
n = 0;
}
// Add one to wherever we got to
n -= -1;
}

// Build up integer part
i = 0;
while ( i < nd ) {
// No commas version;
// r += '' + n[i++];

// Commas version
r += (( (nd-i)%3 )? '' : (0 == i)? '':',') + n[i++];
}

// Add decimal part
if ( d > 0 ) {
r += '.';
while ( i < len ) {
r += n[i++] || '0';
}
}
return r;
}
 
R

RobG

RobG wrote:
[...]
Here's another that can handle any precision and adds commas. Remove
validation and comments and it's only marginally longer that DG's.

I should post sooner, I'd find the bugs quicker...
function formatDecimal(n, d) {
// Is n digit(s) with optional point or optional point and digit(s)
if ( !/^(\d+)[\.|(\.\d+)]*$/.test(n) ) {
return "Number part should be format 0 or 0.0";
}

// Is d an int?
if ( !/^(\d+)[\.|(\.0+)]*$/.test(d) ) {
return "Number of decimal places must be an integer";
}

// nd is number of digits before zero
var nd = (n + '').split('.')[0].length;

// len is total number of digits required
var len = +d + nd;

// n is array of digits with decimal place removed
n = n.replace(/\./,'').split('');

// If there is a digit after required length, do rounding,
var i=len, r='';

// If last+1 digit is bigger than 4
if ( n && n > 4 ){
// While preceding number is 9 and not first
while ( 9 == n[--i] && i > 0 ) {
// Make it zero
n = 0;
}
// Add one to wherever we got to
n -= -1;
}


If the number is 999.9, result is 1000.0 not 1,000.0. Here's the fix:

// Add one to wherever we got to
n -= -1;

// Make sure it's not '10'
if ( 10 == n )
n = 0;
n.splice(i,0,'1');
}

If the 'comma' output is not required, the fix isn't needed.

[...]
 
R

RobG

RobG said:
RobG wrote:
[...]
[...]

// Make sure it's not '10'
if ( 10 == n )
n = 0;
n.splice(i,0,'1');
}


Brain-dead day:

// Make sure it's not '10'
if ( 10 == n ) {
n = 0;
n.splice(i,0,'1');
nd++;
}
 
D

Dr John Stockton

JRS: In article <[email protected]>,
dated Mon, 23 May 2005 11:03:26, seen in
elektrophyte said:
Thank you very much for the replies. As suggested I removed the
getTime() and formatNumber() calls and now it works in Safari. Now I
just need to debug formatNumber(). I got it from Danny Goodman's
JavaScript Cookbook (Oreilly). Maybe I'll just try to write my own
function to format the number.

That would be unwise, unless you need the practice; many have done so
and got it wrong. Instead, read the newsgroup FAQ.
In case anyone is curious, I'll add
Goodman's code below.

// The formatNumber function comes from Danny Goodman's
// JavaScript Cookbook.
function formatNumber (num, decplaces) {
// convert in case it arrives as a string value
num = parseFloat(num);
// make sure it passes conversion
if (!isNaN(num)) {
// multiply value by 10 to the decplaces power;
// round the result to the nearest integer;
// convert the result to a string
var str = "" + Math.round (eval(num) *
^^^^

Pointless. Function parseFloat always returns a Number, even though it
may be NaN or an Infinity.

When replying, please quote, attribute & ignore Lahn :

Keith Thompson wrote in comp.lang.c, message ID
<[email protected]> :-
If you want to post a followup via groups.google.com, don't use
the "Reply" link at the bottom of the article. Click on "show
options" at the top of the article, then click on the "Reply" at
the bottom of the article headers.
 
D

Dr John Stockton

JRS: In article <[email protected]>, dated Tue, 24
May 2005 04:33:00, seen in RobG
Here's another that can handle any precision and adds commas. Remove
validation and comments and it's only marginally longer that DG's.


function formatDecimal(n, d) {


Float arithmetic has rounding errors; therefore, a Number that ideally
would be zero may be slightly negative. Your routine fails with those,
as with genuine negatives.

Also, it fails with input '5e5', though it works with '550000'

It looks rather slow, though I've not checked.

I don't see why one should want a routine that treats its parameter as a
string; but it does work with numbers that more-numeric methods would
find too big.
 
R

RobG

Dr said:
JRS: In article <[email protected]>, dated Tue, 24
May 2005 04:33:00, seen in RobG




Float arithmetic has rounding errors; therefore, a Number that ideally
would be zero may be slightly negative. Your routine fails with those,
as with genuine negatives.

Yes, but the negative part could be easily fixed.
Also, it fails with input '5e5', though it works with '550000'

Yes.

It looks rather slow, though I've not checked.

Takes about 6 times longer than toFixed(), 3 times longer than simple
string truncation methods.
I don't see why one should want a routine that treats its parameter as a
string; but it does work with numbers that more-numeric methods would
find too big.

'cos it's more fun than using toFixed() :)

toFixed() is *the* fastest method and, in the OP's case, if it's not
supported, then simply truncating the decimal cents is likely perfectly
adequate (unless decimal cents are important in what looks like US
military spending or national debt).
 
D

Dr John Stockton

JRS: In article <[email protected]>, dated Wed, 25
May 2005 04:01:53, seen in RobG
toFixed() is *the* fastest method and, in the OP's case, if it's not
supported, then simply truncating the decimal cents is likely perfectly
adequate (unless decimal cents are important in what looks like US
military spending or national debt).

AIUI, when actually doing accounts, the arithmetic must be exact, and in
compliance with applicable rounding rules.

Here, BT has recently announced that, from 2005-06-17, billed VAT will
be rounded up, rather than down, to the nearest penny. In either case,
small rounding errors such as can be expected when using non-integers
can flip the result from one state to another, when the nominal
calculation gives an exact result.

Wasting a few billion is another matter, of course; only to be expected.
 
T

Thomas 'PointedEars' Lahn

elektrophyte said:
[...]
// The formatNumber function comes from Danny Goodman's
// JavaScript Cookbook.
function formatNumber (num, decplaces) {
// convert in case it arrives as a string value
num = parseFloat(num);
// make sure it passes conversion
if (!isNaN(num)) { ^^^^^^^^^^^
// multiply value by 10 to the decplaces power;
// round the result to the nearest integer;
// convert the result to a string
var str = "" + Math.round (eval(num) * ^^^^^^^^^
Math.pow(10,decplaces));

OK, at least from now on Goodman can no longer be considered a viable
source for JS information either. Sometimes I hate it when I'm right.


PointedEars
 
R

Richard Cornford

Thomas said:
OK, at least from now on Goodman can no longer be considered
a viable source for JS information either.

No change then. Danny Goodman has promoted the most extraordinary -
eval - abuses over the years, and much else that is positively
discouraged by the competent.

Richard.
 

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,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top