Scraps of JavaScript
Listen to this article
Not much today but some little bits-and-pieces of stuff I've picked up over the last two weeks. It's been a steep learning curve going from no JavaScript to writing a character-based terminal emulator and it's sure been fun.
Now that I have a modicum of JavaScript under my belt, I think I'll finally take Big Daz' advice and have another look at prototype. I had a quick look initially—on his recommendation—but I was so new to the language that none of it made much sense. FWIW, thanks again to Big Daz, I also spent a lot of time reading quirksmode.org.
Overall, DHTML works really well. The browsers seem to handle running JavaScript pretty well -- the performance is quite impressive—and it's not that difficult to get things to work cross-browser.
So, here we go...
Rather than report an error, most browsers seem to silently fail or at best give a rather less than helpful message -- either by way of a pop-up or a message to the JavaScript console.
The error messages in Mozilla—sent to the JavaScript Console—are far more useful than those generated by Safari -- also sent to the JavaScript Console; MSIE is woeful when reporting (by way of a pop-up) errors in JavaScript files that have been included via <script language="javascript" src="..." type="text/javascript" />.
The debugger for Mozilla works a treat.
Methods can't be named the same as fields—they're really just the same thing anyway. Not really a problem but I was translating some code to JavaScript and it didn't work out as I had planned ;-). Either use an underscore (_) for field names; make sure your method names are always prefixed with a verb such as get/is/etc.; or "allow" direct access to fields. I say "allow" because strictly speaking, it seems that field values are pretty much always accessible anyway.
Closures usually require that you define a variable with a value of this to ensure you can always refer back to the object that owns the function being called:
var self = this;
orders.each(function(order) {
self.process(order);
});
To ensure your onkeypress event handler is called with an event object, use something like the following to capture the event and then delegate:
var self = this;
document.onkeypress = function(event) {
return self.onkeypress(event ? event : window.event);
}
To have a keystroke ignored seems to require the following code in your onkeypress event:
event.cancelBubble = true;
event.returnValue = false;
return false;
This works for most everything with the noteable exception of F1 in MSIE which displays help on the browser. To prevent this, try:
document.onhelp = function() {
return false;
};
The Mac generates very odd key codes for things such as Up (63232), Down (63233), Left (63234), Right (63235), etc. I say odd only because I'm used to the ones generated on PCs (38, 40, 37, 39, ...). Ok, so maybe they're not odd just different ;-)
MSIE seems only to allow you to modify the content (DHTML) of a div.
Even though the HTTP protocol allows you to send and receive binary data -- using Content-Type: application/octet-stream and Content-Transfer-Encoding: binary for example --- none of the browsers I tested would reliably allow the JavaScript code to receive that data as a string of characters, even though the browser would quite happily download the content to a file on my hard-disk and allow me to manually construct a string with identical content -- using String.fromCharCode(0x1b) for example.
You can simulate Swings invokeLater by using window.setTimeout() with a time-out value of zero:
var self = this;
window.setTimeout(function() {
self.doSomething(...);
}, 0);
Most of the browsers I tested didn't seem to support for .. in ..; they all accepted the syntax but produced kooky results when used.
All browsers I tested support using innerHTML to replace the content:
document.getElementById(id).innerHTML = html;
Using a span with CSS classes is the simplest way to inline style changes:
<span class="important">...</span>
Handling errors (and for that matter state changes) when using XMLHttpRequest (or in the case of MSIE, ActiveXObject("Microsoft.XMLHTTP")) differs between browsers:
- Safari and MSIE seem to always set
request.statusandrequest.statusText; - Netscape/Mozilla seem to sometimes set these variables, yet other times throw exceptions due to the varible having not been defined;
- Most will allow any old value for request method and URL and notify you via
onreadystatechangeif there was an error -- such as 404 Not Found for example -- though sometimes (under what circumstances I don't recall) they will throw an exception onopen()and sometimes onsend().
Both Netscape/Mozilla and MSIE append a CRLF (0x0d0a) to the end of any content you send, leaving the Content-Length field two-bytes short; Safari seems to leave the content as-is. Not really a problem but interesting as the data already had the CRLF as usually recommended for sending content via HTTP.
To change the colour of a horizontal-rule (<hr class="a_style" />) in a browser-neutral manner, you need to set your CSS style as:
hr.a_style {
background-color: #NNNNNN;
color: #MMMMMM;
border: 0;
height: 1px;
}
You can call a method using a string for the name, allow a switch-like calling mechanism:
var methodName = (this.insertMode) ? "insert" : "overwrite";
this[methodName](aCharacter);
More to come I'm sure. Add any more you can think of or let me know of better ways to do these things as I'm truly ignorant in this space.
Comments
I would advise you to check out the JavaScript frameworks Prototype and script.aculo.us (http://script.aculo.us). They have solved some of the above incompatability issues and are offering a consistent API which works cross-browser. In contrast to other similar frameworks they're quite simple and don't try to reinvent the entire world. Also they readily accept patches if there's other cross-browser issues you come up with and solve.
Have fun! I'm really starting to enjoy working in JavaScript!
Cheers,
Jon
Posted by: Jon Tirsen | August 23, 2005 03:09 PM
Ohh... Sorry, I didn't see Big Daz had already pointed you in the direction of Prototype. Yeah, follow his advise too. :-)
Posted by: Jon Tirsen | August 23, 2005 03:11 PM
"...Even though the HTTP protocol allows you to send and receive binary data -- using Content-Type: application/octet-stream and Content-Transfer-Encoding: binary for example --- none of the browsers I tested would reliably allow the JavaScript code to receive that data as a string of characters,..."
I've got a working code which allows to fetch a binary stream from a server and receive it reliably as a string of bytes in Firefox. Have a look at http://mgran.blogspot.com/2006/08/downloading-binary-streams-with.html
[]s,
Marcus
Posted by: Marcus Granado | August 22, 2006 10:01 PM
Hi there, I couldn't find any way to e-mail you, so I guess that is what this is.
You mentioned writing a terminal emulator in Javascript, would the source by any chance be available for that?
The next time you're in Sweden, drop by our Aikido club, Stockholm Aikido (www.stockholm-aikido.nu) for a few sessions.
Cheers//JoHo
Posted by: Joaquim Homrighausen | November 7, 2006 10:10 AM