in my experienceI approached the problem by using ASCII character codes. If you have BBEdit, there's a pallette that shows all of those code next to their characters, so I used that to write an annoyingly long if statement with four "or" statements and two "and" statements imbedded in an or statement. Annoying, but effective. Here it is...
function alphaNumericCheck(theChar) {
if ((theChar < 48) || (theChar > 122) ||
((theChar > 57) && (theChar < 65)) ||
((theChar > 90) && (theChar < 97)) ) {
return false;
} else {
return true;
}
}
To call the function, you would say something like...
<input type="button" name="foo" value="my button"
onclick="alphaNumericCheck(this.value.charCodeAt(0))">
The part that says charCodeAt(0) will return the ASCII number for the character at the zeroth position in the string (the first character). The function will take that character and return "false" if it's not a number, a capital letter or a lowercase letter, and "true" if it is alphanumeric. Try it.
function reportFormElements(obj) {
for (var i = 0; i < obj.length; i++) {
if (obj.elements[i].type == 'checkbox') {
alert(obj.elements[i].checked);
}
else {
alert(obj.elements[i].value);
}
}
}
The basic gist is, for each actual form element in the form, look at the value of the form element and alert that value. If it's a checkbox, then investigate the 'checked' attribute.
There are several ways to do this sort of thing, and one of them reports the value of each child node in the named form, including text nodes, html nodes. We don't want that, and only want to interrogate the actual form elements. A sample form is below, go ahead and try it...
var input = document.createElement("INPUT");
input.setAttribute("type","text");
input.setAttribute("name","myinput");
input.setAttribute("id","myinput");
That makes a new input element, and then sets all of the attributes and their values. The result should be something like this...
<input type="text" name="myinput" id="myinput">You can try that code right here... When you click on "Add an Input" some more complex JavaScript than quoted above will execute, and if you are using Navigator, Safari or Mozilla, you will get a new input with all if its necessary attributes defined and populated. The innerHTML will be alerted so you can verify that. Try it, and then view the page source to see what the code is doing.
Notice that I used the word "should" in the my comments above. I say the 's' word for a couple of reasons. Internet Explorer 6 on Win 2k Pro doesn't set any of the attributes. And Internet Explorer 5.2.3 for Mac OSX does something even worse, it throws a JavaScript error on the attempt to set the type attribute. Scouring the net for answers yielded frustrating results.
One particularly delicious find mentions that the Microsoft Developer site provides code that doesn't execute. When I run the code at that link, I get an error at the attempt to set the type attribute. The MSDN even talks about the method as if it were fully supported, but I'm not so sure about that. The only working example I could find seems to be completely IE/Windows specific and mentions that "his method requires an object participating in persistence".
My conclusion is that the setAttribute method is not fully supported in Internet Explorer. So, we resorted to workarounds, and found one. If you do a createElement("SPAN") and then pump it full of innerHTML and then append that to something, you will get your desired effect. But, that's at the price of using non-DOM code.
If anyone else can shed any more light on this, please do. My knowledge on the subject is anecdotal and derived from experimentation. Other data includes weird comments like the following from O'Reilly...
"The book says that the setAttribute() method in IE4 through 5.5 uses propertynames instead of attributenames. I experienced that the same behaviour holds for IE6.0 for PC."Again, please let me know if you know anything that hasn't been mentioned here already.
This is how yesterday's discussion about the getYear() method started. We are using that call in one script to deal with population of date fields (everything is tracked, and everything gets a time stamp). This effort is a classic example of why JavaScript, new browsers, and NOT following standards can cause extra work down the line.
Our server logs tell us that about 20 percent (I don't remember the exact amount, but it's much larger than "non trivial") of our users are Safari users, so this compatibility effort is essential. The saving grace is that the date functions we/I have written, are all in one place and sufficiently abstracted, and that helps me do less work. I had to add two lines of code to fix stuff. The hard part was doing the forensic work via alert() calls.
If I was smarter (and didn't use deprecated date methods), I wouldn't have had to make any edits, and Safari would have been auto-supported. Lesson learned.
Many thanks to those who posted yesterday.
cells[] array broken in Safari (?)
June 26, 2003 2:08 AM
Safari reports the length of the cells[] array of a table row as zero, even if it has multiple cells. Look at the table below, if you mouse over it in a Gecko browser, or IE, you will see the background color of the table cells turn color. We do this by placing an onmouseover in the TR tags...
<tr onmouseover="color(this)">And that "color" function takes over and says...
function color(obj) {
for (var i=0; i < obj.cells.length; i++) {
obj.cells[i].style.backgroundColor = '#FFFFCC';
}
}
So, onmouseover, the TR object gets passed and the function runs a loop using the length of the TR cells[] array as a stop point. In each iteration of the loop, it sets the backgroundColor to a light yellow and then we use an onmouseout to clean up after it, using almost the same exact function, only with a different name and different color (in this case, light grey, or #CCCCCC).
| _Row_1_Cell_1_ | _Row_1_Cell_2_ | _Row_1_Cell_3_ | _Row_1_Cell_4_ | _Row_1_Cell_5_ | _Row_1_Cell_6_ |
| _Row_2_Cell_1_ | _Row_2_Cell_2_ | _Row_2_Cell_3_ | _Row_2_Cell_4_ | _Row_2_Cell_5_ | _Row_2_Cell_6_ |
| _Row_3_Cell_1_ | _Row_3_Cell_2_ | _Row_3_Cell_3_ | _Row_3_Cell_4_ | _Row_3_Cell_5_ | _Row_3_Cell_6_ |
| _Row_4_Cell_1_ | _Row_4_Cell_2_ | _Row_4_Cell_3_ | _Row_4_Cell_4_ | _Row_4_Cell_5_ | _Row_4_Cell_6_ |
[I don't mean to pick on Safari this week, I just happen to be dealing with it a lot and am finding some issues. I'm trying to help out by writing test cases and send them to the mother ship.]
[Update: Safari 1.1 doesn't fix the cells[] array.]
[Update: Safari 1.2 (which is Panther only) fixes the cells[] array.]
getYear() in Safari == getYear() in Navigator 4.x
June 25, 2003 11:55 AM
Ok, so this is weird, and I don't know why it was done this way (maybe Dave can explain), but Safari 1.0 returns the same value for the getYear() method that Netscape 4.x does, 103. Check this script out and then go ahead and click the button to see what it returns...
<script type="text/javascript" language="Javascript1.2">
function showYear() {
var nowX = new Date();
var theYear = nowX.getYear();
alert(theYear);
}
</script>
var isMinNS4 = (navigator.appName.indexOf("Netscape") >= 0
&& parseFloat(navigator.appVersion) >= 4
&& parseFloat(navigator.appVersion) < 5) ? 1 : 0;
And we can do something similar for Safari by saying...
var isSafari = (navigator.userAgent.indexOf("Safari") >= 0) ? 1 : 0;
This basically says that the var "isSafari" is equal to "1" if the string "safari" occurs in the navigator.userAgent object. If it doesn't, then the value is 0, and later on we can use that value to say...
if (isMinNS4 || isSafari) { theYear += 1900; }
Which says that if it's Nav 4 or Safari then make "theYear" equal to itself plus 1900. And even us forensic JavaScripters should be able to figure out that 1900 + 103 = 2003. So, to get Safari to tell you what year it is, we can use this function...
<script type="text/javascript" language="Javascript1.2">
function showYear() {
var isMinNS4 = (navigator.appName.indexOf("Netscape") >= 0
&& parseFloat(navigator.appVersion) >= 4
&& parseFloat(navigator.appVersion) < 5) ? 1 : 0;
var isSafari = (navigator.userAgent.indexOf("Safari") >= 0) ? 1 : 0;
var nowX = new Date();
var theYear = nowX.getYear();
if (isMinNS4 || isSafari) { theYear += 1900; }
alert(theYear);
}
</script>
I can't even begin to support Safari until the JavaScript engine is fixed, and hopefully the final production version of Safari will be pretty solid, but even then, I know I'll be tweaking our scripts. Just call me Sisyphus.
Setting a maxlength on a textarea.
February 15, 2003 10:36 AM
On a mailing list last week someone asked about placing a maxlength on a <textarea> which most
HTML munkies will know is not a legal (or supported) attribute of that tag. Someone chimed in making that point and suggested that the person get familiar with the HTML 4.01 DTD. That advice is in the vein of 'if you teach a man to fish, you feed him for a lifetime.' I'm going to take the other tack and give the man a fish.
Most (all?) web browsers have onkeydown and onkeyup and onkeypress implemented as event handlers for the textarea tag. So we can use any of those to detect when a user is typing something into that field, and count the length of that field, and warn the user when they have passed an arbitrary maximum length that we choose. First, we make a <form>, a <textarea> and a place to show how many characters are remaining...
<form name="maxlength_test" action="who_cares" method="">
<TEXTAREA NAME="something" ROWS="10" COLS="50" onkeypress="textCounter(this,this.form.counter,255);"> </TEXTAREA> <br> <input type="text" name="counter" maxlength="3" size="3" value="255" onblur="textCounter(this.form.counter,this,255);"> chars remaining </form>
The form name doesn't matter because we use 'this' as a object model handle back to the form to operate on the elements within it. The name of the textarea does matter, so be sure you set that correctly. In the textarea, the onkeypress fires when a user pushes a key in and the key comes back up while typeing in the text area. The JavaScript function called "textCounter" gets a few variables passed to it. First, the textarea form object, the textarea's form object called 'counter' and a number. That number is the maximum length that the text area can be.
The function looks like this...
function textCounter( field, countfield, maxlimit ) {
if ( field.value.length > maxlimit )
{
field.value = field.value.substring( 0, maxlimit );
alert( 'Textarea value can only be 255 characters in length.' );
return false;
}
else
{
countfield.value = maxlimit - field.value.length;
}
}
The function basically says if the textarea object that was passed in is longer than the number that was passed in, then set that textarea back to the length that we passed in, and alert the user about the maximum length. Otherwise, set the 'countfield,' which we passed into the function as "this.form.counter," to the maximum length minus the current length. Thus we get a count down.
And that's pretty much it. If you are using PHP or Mason or something, you can fill in the max length number in a variable, and let that get handled on an arbitrary basis. Pretty sweet. A working version of the text area is below, but first, note the following. I didn't write that JavaScript, Sprint did. I needed to set a max length of textarea for a project, so I found someone who did it already, and adapted it to my needs. This is a nice little bit of code that improves the usability of the form by informing you of any limits on data. Enjoy.
edit: Fixed entry that was truncated
I'm not sure why, but different domain names on different pages of a site makes me trust that site less. Why do you need one page of the site to live at an entirely different domain? I understand putting a file to download at a diff site (such as Akamai) for caching or download speed, but other normal pages of the site should be within the same domain. I don't know why, but it bugs me.
Who cares though, it all runs on JavaScript, and I know JavaScript, so I'll be tinkering with this soon.
You need a crutch when your leg is broken.
June 18, 2002 9:52 AM
ScottAndrew wonders what he really feels about JavaScript crutch libraries. I don't. I like them, welcome them and hope people learn from them. Personally, I find myself in a fire drill environment where a solution to a problem has to come as quickly as possible (sound familiar?). I keep a directory of old JavaScripts on my machine as reusable code libraries, but of course, as time goes by, they go stale, and Murphy's Law says I'll need the most stale script on a moments' notice. If I can get that working with minimal effort and deliver reliabel, functioning code, then I've put out the fire. When I have time, I go back to make the code clean, elegant and proper. I'll call this being resourceful.
Scott's point is not lost on me though, and I agree that correct, modern, validated, tolerant and gracefully degrading code is a best practice. Sometimes you just have to fill in the cracks and repave later (time and budget permitting).