Latest News
![It has good parts? [It has good parts?]](/img/jstgp.gif)
I recently finished reading Douglas Crockford's Javascript: The Good Parts from O'Reilly Media. This slender book cannot be considered a complete reference guide to Javascript, nor a primer on programming. The author mostly avoids discussing how the language works in web browsers, the natural habitat of Javascript.
Instead, this book is meant to introduce a subset of the language that the author believes to be the most useful to the reader and the least likely to cause harm. If this seems like presumptuous concept for a book, you're mostly right. Javascript is best used in small doses only at need. However, as a author of the Javascript Object Notation format, Crockford does have the bona fides to make such recommendations. As it turns out, many of those recommendations are worth following.
The book clocks in at about 145 pages and ten chapters. Seven of those chapters introduce the major components of the language: grammar, objects, functions, inheritance, arrays, regular expressions and methods. As I said, this book is not for novices, but one could (maybe) pick up the language from these chapters. If one is already familiar with the language, Crockford does provide some valuable insights into how the language actually works as opposed to how most of us expect the language to work. Of particular note are the sections on objects, functions and regular expressions.
Chapter 10 is a bit of let down. It's call "Beautiful Features." After reading 100 pages of syntax and commentary, I expected to have a rather lenghty exposition of the wonderful things that can be done in the subset of javascript previously described. However, that is not what this two page chapter is about. Instead, this is a sort of conclusion with some hand waving. There is meat in the appendices that follow. Perhaps this chapter was originally all of the appendices concatenated together and the editors split them. That sort of thing does happen.
Throughout the book, Crockford blithely offers such commentary on Javascript like "[That all object properties are public] is a serious design error in the language" or "Because of a design error, arguments is not really an array." The pedantic voice of the author will grate on some reader's nerves. The tech world is full of such writers. If this affectation can be ignored, there is useful content here that will demystify javascript's weird functional, classless object system, it's prototypical inheritance scheme and it's somewhat weird function parameter access. But frankly, I was expecting a book a lot more like Pike's The Practice of Programming but in a javascript context.
jQuery in Action by Bear Bibeault and Yehuda Katz is a fine introduction into the wonderful jQuery. jQuery is a free javascript library that significantly eases the burden of manipulating the Document Object Model found in modern web browsers. The library has a distinctly functional feel to it, much like LISP. After reading this book, I'm humbled by the incredible job the architects of jQuery did in making such a clean and incredibly useful API. jQuery also bares the marks of Perl in its .map and .grep functions, and so warms the cockles of my heart.
Bibeault and Katz gently introduce the reader to this powerful library without overloading him with too much theory up front. This is not to say that the book is light on details. It is not. However, the less immediately useful details are pushed to the back of book. I found the Appendix on Javascript's damnabled Object system to be the most enlightening of all. While I understood the classless object system of Javascript before I read this, I did not really get the scoping rules (and I continue to be appalled at the insanity of it).
The order of the material is very reasonable. It begins with a bit of the philosophy of Unobtrusive Javascript, and then explains how to find DOM elements with jQuery selectors, how to manipulate those wrapped sets, how to install javascript events and how some of the built-in animation effects and utility functions work. All this is followed by a chapter on extending jQuery with plugins, a giant 50 page chapter on Ajax and a survey of useful plugins that are available on the jQuery site.
The highlights of this book include the discussion of Unobtrusive Javascript. This is literally a new concept to me and one that is much welcomed. The many references to the W3C HTML and DOM specs took me back a bit. During the ugly years of the Browser Wars, these specs were little more than wishful thinking. Yet now, most broswers (not IE) try to adhere to these documents. That's quite a sea change! The madness of event handling in DOM levels 0 through 2 is Lovecraftian (and perhaps explains a bit more of the problem my tic-tac-toe client has with IE).
The book is filled with practical examples of jQuery at work. The authors even have created little online tools to demostrate these concepts. I didn't find these to be all that useful, but I think I'm not the target audience. I'd rather come up with my own projects and apply these ideas to them.
I recommend this book to novices and pros alike who wish to get up to speed quickly on the use and philosohpy of jQuery.
As part of my technological foraging, I have been playing around with Ajax as presented through the new hotness that is jQuery. The result is a very humble, but all Ajax, tic-tac-toe game. This replaces the all flash version I had on this site for a while. Not only did I improve the AI of the computer player (thanks CS210!), but I have completely validated HTML and CSS files to boot.
Part of my inspiration comes from my current nighttime read, jQuery in Action by Bibeault and Katz. Besides gently easing the reader into jQuery concepts, the authors turned me on to the concept of unobtrusive javascript, which is the idea that HTML, CSS and javascript should be kept separate from each other, thus simplifying development considerably. One way to intrepret this concept is that HTML, CSS and Javascript all need to be keep in discrete files. That means no "onClick" attributes in the HTML, please. In structure, one can find liberation.
The architecture of my tic-tac-toe game follows a pretty standard client-server model. The server bit consists of a single PHP script that handles game session and AI. The client bit is simply an HTML file supported by CSS and Javascript. The client API is narrowly defined to prevent obvious forms of cheating and to enforce the idea that the client is a display and input mechanism that has little idea about how to play tic-tac-toe. The game logic is enforced by the PHP script. I'll discuss the design of the game engine later, but let's look at the client first.
The entire source for tic-tac-toe can be found here.
The place to begin with the tic-tac-toe client is the index.html file. This is a validating HTML 4.01 Transitional document. It has no TABLE tags at all. It depends on CSS float to make the playing board and handle the rest of the page layout. Because of some problems with Internet Explorer, there is a bit of IE-specific goo that forces a warning to appear in that browser. That will be the subject I return to last.
That HTML file is so clean, you could eat off it. Anyone who has done PHP or even a lot of javascripting will be surprised that such a simple file could be the basis of anything complex. As far as the game is concerned, the most interesting elements in the HTML file are the DIVs that have an ID attribute beginning with "s". In traditional video game parlance, these function as both buttons and sprites. I could have used HTML buttons here. Part of me still thinks that's the right way to go, but just using DIVs looks a lot more "gamey" to me. All the wiring of event handlers for these DIVs is handled in the ttt.js file, described shortly. The look and layout of the client is provided by the ttt.css file, which holds no surprises.
The client-side magic happens in the javascript. As it promises to do, the jQuery library greatly reduced the burden of locating and attaching elements, attaching click handlers and Ajax processing. Because the jQuery library is loaded before ttt.js, jQuery functionality is accessible in this file. The first four lines of code are pretty harmless:
var Game = new Object(); Game.timeout = 5000; Game.square_clicker_enabled = false; $(document).ready(init);
A global object called Game is created that will hold client-side game state. Scoping in javascript is a little primative, so having one global object in which to store various bits of information helps to reduce namespace clutter. The game property 'square_clicker_enabled' is set to false to prevent undesirable button clicking later on. I'll get to that. The most powerful statement here is the ready() function that calls init() (not shown yet) when the DOM is fully constructed in the browser. As any primer on jQuery will tell you, the more traditional onLoad() event for BODY elements does not run untill all the graphics are loaded on the page. The ready() function is ideal of initialization code. Speaking of which...
function init() {
$("#newGame").click(new_game_clicker);
var arg = new Object();
arg.get_board = 1;
$.ajax({url: 'move.php',
type: 'GET',
data: arg,
dataType: 'json',
timeout: Game.timeout,
error: bomb,
success: function(a) { paint_board(a);}
});
}
The init() function sets up the click handler for the "New Game?" button/DIV that ensures a new session and a blank board on the server. The fancy jQuery selector simply looks for an element with the ID of newGame. An object is created to hold parameters to be passed in the following Ajax request. The call to "get_board" simply requests the board state of the current game, if applicable. If the call is successful, the paint_board() function is invoked with the structure returned from the server. Even though the server returns a JSON serialized string, jQuery deserializes this structure and passed it to the function. That's some pretty terse code for an RPC mechanism!
function new_game_clicker() {
if (confirm("Really start a new game?")) {
var arg = new Object();
arg["new"] = 1;
$.ajax({url: 'move.php',
type: 'POST',
data: arg,
dataType: 'json',
timeout: Game.timeout,
error: bomb,
success: function(a) { paint_board(a);}
})
}
}
There's little new code here at all. All veteran javascripters will have seen the confirm() dialog function. The click handler for the new game button is mostly another Ajax call. This one creates a new session and empty tic-tac-toe board on the server. Again, whenever the state of the board might have changed, paint_board() needs to be invoked.
function square_clicker(e) {
if (Game.square_clicker_enabled) {
Game.square_clicker_enabled = false;
var arg = new Object;
arg.pos = this.id.charAt(1);
$.ajax({url: 'move.php',
type: 'GET',
data: arg,
dataType: 'json',
timeout: Game.timeout,
error: bomb,
success: function(a) { paint_board(a);}
});
} else {
alert("Thinking!");
}
}
The click handler of each game board square is a little trickier. At its heart, the handler is merely responsible for sending the human's move to the computer using an Ajax call. When the player moves, the computer also makes a move and the new board state is returned and passed to paint_board(). Again, there are a lot of details behind that tiny bit of code!
The Ajax call is protected by a boolean. The idea is to prevent humans from wildly click on squares before the computer returns with the new game state. The opening move for the computer can take a few seconds to calculate, even when the depth of recursion is limited! I suppose that's why algorithms with a runtime performs of O(n!) are frown upon.
As simple as this mechanism is, Internet Explorer does not seem to like it very much. When I use that browser, I get all kinds of weird board states. It is a mystery to me why this happens, but this is why I include a warning to IE users in the HTML document.
function paint_board (a) {
if (a.board == null) {
$("#status").text("No game in progress");
Game.square_clicker_enabled = false;
} else {
for (var i=0; i < a.board.length; i++) {
$("#s" + i).empty();
if (a.board.charAt(i) == '0') {
var events = $("#s"+i).data("events");
if (events == null) {
$("#s"+i).click(square_clicker);
}
} else {
$("#s"+i).unbind('click',square_clicker);
var e = a.board.charAt(i).toUpperCase()
e = $("<span></span>").text(e).addClass("p");
$("#s"+i).append(e);
}
}
Game.square_clicker_enabled = true;
if (a.msg == null) {
a.msg = " ";
}
$("#status").text(a.msg + " ");
}
}
Finally, the heart of the client code appears in paint_board. Given a structure from the server, it displays the game state on the board to the human. The board's state is presented as a nine character string where each position represents a place on the board. A zero is an unoccupied space, an 'x' represents the human's move and a 'y' represents the computer's. Notice that the client doesn't even know that much. It simply knows that 0 states are presented one way and non-zero another.
When the board is painted, the square_clicker_enabled flag is set to true, allowing the human to make a new move. If an open square is indicated by the board state, a click handler is installed if one does not exist. If the square is occupied, the click_handler is removed. Doing this without jQuery would have been horrible.
And there's the client! Amazingly small and even valid HTML. Will wonders never cease?
This post is already long. At some point, I'll go into the server code which has some moderated clever AI and some awful code to determine a win condition. Keep reachin' for the stars!
XHTML is a great idea, once you understand the shear Lovecraftian terror that is SGML, of which HTML is a child. Very few people understand all of SGML, including me, but here's the important point: SGML has all kinds of rules to imply elements. If you don't close your OPTION tag in HTML, the browser will create a node for the end tag anyway when in interprets that document. That's great, but in the case above, the browse does something completely predictable. However, there are plenty of ambiguous cases of what missing nodes should be created and trust me, brother, you don't want to go there. But this is a horrid topic for another day.
The problem with XHTML is that it is XML. So when you need to add a SCRIPT section, you need to escape it XML-style like this
<script type="text/javascript">
<![CDATA[
{js code here}
]]>
Wow! That's ugly! But wait, there's more. No Javascript engine knows anything about XML CDATA blocks so you need to hide that with Javascript style comments. So you get this:
<script type="text/javascript">
//<![CDATA[
{js code here}
//]]>
What a mess! If this alone doesn't make you run for keeping your JS in a separate file, nothing will.
A feature I wanted for my Spycam page is an animated loop of the last 5 pictures. All the pictures are in PNG format. There are several techniques that would accomplish this: GIF animation, SVG/Flash and JavaScript. I choose to use a pure JavaScript (or ECMAScript, to be politically correct) solution, which I'll detail in a moment. But first, I'll briefly talk about the alternatives.
Animated GIFs have been around nearly as long as the web. Here is an example of one that I created for my late Aliens, Aliens, Aliens web site:
The GIF file format allows for multiple frames and timing instructions for the pace of animation. At first, I thought I could do the same kind of animation with PNG files, but that format does not allow animation. With image manipulation libraries, I could create a new GIF and stuff it with frames converted from the five most recent spycam photos. However, that seemed like a lot of work and I didn't really want to create yet another file to keep track of. However, the advantage of this solution over the one I choose is that it scales better. That is, by serving a static animated GIF, taskboy.com vistors will not be continually pulling down an image for each animation loop. It's true that most browsers cache web assets, so it's likely that once the frames are loaded in the JS animation scheme, taskboy.com will be left relatively unmolested.
The next solution that occurred to me was to create a Flash SWF file of this loop. However, I'm not much of a Flash guy, nor am I emotionally ready to invest the time to learn the Perl interface to it. Of course, there is the XML-based, open source alternative to Flash called SVG. SVG does support animation, as you'd expect, but many browsers including Firefox do not yet support SVG animation. This was quite disappointing.
Finally, I hit on the relatively old idea of periodically switching the photo using DOM manipulation. The code to do this works in modern browsers (even IE 6). In pseudo-code, the strategy looks like this:
- Setup an array of images in order from oldest to newest
- Look for a well-known ID block and update the attributes of the child IMG tag with the next image in the array
- Update the description in a well-knwon ID block
- Schedule steps 2-3 to run again after a brief delay
Consistent browser support for DOM manipulation directly led to the Web 2.0 explosion of the early 2000s. It is possible to use Javascript to add, remove and edit nodes of the document tree in a consistent way across all major browsers. For those of you too young to remember, this was not always the case. There was an ugly time, known as the Browser Wars, that left many a young Javascript programmer mamed and bitter.
Let's back into this code from the HTML. After all, this is the structure to be changed dynamically. Fortunately, this document structure is pretty simple:
<div id="animator" align="center"> <div align="center" id="pic_desc"></div> </div>
This is simply a DIV block (ID = "animator") that encloses another DIV (ID = "pic_desc"). Where's the image tag? That will be inserted dynamically later and put ahead of the second DIV. However, an empty IMG tag could be added to the HTML right at the start. This will save some complexity in the Javascript later on, as will be noted.
The Javascript for this isn't complex in concept, but it may look a little daunting. However, it consists only of one globally scoped array and one function.
var Pictures = new Array("2009-09-24_21-10-01.png",
"2009-09-24_21-11-01.png",
"2009-09-24_21-12-02.png",
"2009-09-24_21-14-01.png"
);
function show_next_image(last_index) {
// Calculate the next image's index
last_index = (last_index + 1) % Pictures.length;
// Find right element
var e = document.getElementById("animator");
if (e != null) {
var i = null;
for (var j=0; j < e.childNodes.length; j++) {
if (e.childNodes[j].nodeName == "IMG") {
i = e.childNodes[j];
break;
}
}
if (i == null) {
i = document.createElement("img");
e.appendChild(i);
}
i.setAttribute("src", Pictures[last_index]);
i.setAttribute("title", Pictures[last_index]);
// Update description
e = document.getElementById("pic_desc");
if (e != null) {
var t = null;
if (e.childNodes.length == 0) {
t = document.createTextNode("");
e.appendChild(t);
} else {
t = e.childNodes[0];
}
t.data = Pictures[last_index];
}
}
setTimeout("show_next_image("+last_index+")", 5000);
}
The global array, Pictures, isn't difficult to understand. However, how those values are generated might be somewhat non-obvious. Recall that Javascript executes in the client's browser, which is to say, not on the server. How can the array known which files are current? The client doesn't have access to this information. The answer is that the PHP script on the server must determine these values. The script has access to the server and can see all the available files. The PHP code then has to generate the list of filenames that appears in the rendered Javascript code. This is the sort of thing that makes CGI scripting a little mind-blowing at times. You write code in one language that generates code for another.
The function, show_next_image(), depends on the global Pictures array. It is called with index of element of Pictures used previously to update the IMG tag. The % operator may not be familiar to you. It is the modulus operator. It returns the remainder of the integer division between its operands. It has the handy property of generating values between 0 and right-hand value. So, n % 4 never generates values greater than 3. To determine the index of the new Pictures element to display, the passed-in last_index is incremented and the result modded by the length of the array. After all, it is desirable that when the last image in the array is used, the next image should be the first image in the Pictures array.
After determining which Pictures element is to be used, the DOM needs to be examined to find the right nodes to update. Here, the getElementByID() function is used to find the parent DIV. Initially, this DIV has two nodes as written: a text node containing a new line and another DIV. The enclosed child nodes are searched for one that is an IMG tag using the slightly misnamed nodeName property. If such a node is found, its reference will be stored in i. If no node reference is found (as will happen in the initial run), a new IMG node is created with createElement(). All nodes except text nodes are created with this DOM function. The new node then is added to the list of child nodes that the animator DIV has.
I need to point out to anyone following this code carefully that a small display bug has been introduced in this code. If there is no initial IMG tag, the created IMG node will appear below the description, which is undesirable. To prevent this, I simply have an empty IMG tag in the HTML about the "pic_desc" DIV. If you want a pure solution that does not require this HTML stuff, feel free to leave your solution in the comments section of this entry.
An empty IMG tag isn't useful. An IMG node requires at least one attribute, SRC, to do something visible. The SRC attribute tells the browser where to fetch the image to be displayed. This is exactly the information that is stored in the Pictures array. Each element is the relative path to a graphic asset on my server.
Although it is possible to set node attributes with a number of different syntaxes, I recommend always using the setAttribute() function. Not only does it work with all kinds of DOM nodes in all major modern browsers, but if the attribute does not current exist in the node, it is created. This Do What I Mean behavior may be a legacy of Perl, but I can't be sure. Certainly, I don't see a lot of other examples in DOM where one gets a free lunch.
Once the picture is updated, the description follows. The only thing really different about this node manipulation is that it deals with a text node. Text nodes are the stuff that falls outside of HTML tags. This includes the oft-forgotten newlines that are common in hand-written HTML documents. Text nodes are created with the appropriately named createTextNode() function. The text in a Text node is updated through its data property. The pic_desc DIV should only ever have one node that is a Text node. If it has one, it is updated. If not, one is created and inserted as a child of that DIV. Then the data property is updated.
The most interesting part of this code is also the shortest bit. The DOM function setTimeout() takes two arguments: a string that represents code to be executed at some future date and delay in milliseconds that the browser will wait before executing. Notice that the code to be excuted is a string. That is, it will be eval'ed when the delay time elapses. Eval'ed code is a little weird the first time you run into it. It's code that you write at runtime to be executed at runtime. Most code is traditionally written before compile or interpreter time. In this case, I want to schedule this function, show_next_image(), to run again. You'll notice that this will cause the function to run forever, which is the desired effect.
A quick word about the delay setting in this function. In my testing, I found the delay value unreliable. Here, 5000 milliseconds are specified, but I believe the real-time delay between executions of this script were much shorter. Is there a way to create a more highly reliable counter? You could keep track of when time last went off and make decisions about whether to run again, add or substract a delay. If you're trying to write a game in JS with 20 updates per second using this method, you've gotten on the road to perdition.
The last bit of code needed to kick off this animation extravaganza is something that initially invokes the code. In this simple example, using the onload event for body will work well.
<body onload="show_next_image(-1)">
This executes only once when the page is loaded and calls the desired function with an index before the first one. If calling show_next_image() with a -1 index seems like a cheat to you, you can rewrite the function so that it detects when it is called with a null value and assigns 0 to last_index. For me, I'll stick with -1.
If you did not want to use DOM events to invoke this function, you could simply put a script section at the bottom of the BODY tag that called show_next_image(-1) (or its moral equivalent).
Mastering this simple DOM technique opens the way for much more sophisticated work. But that's another post.
Of late, I've had to think about mechanisms to protect web forms from getting spammed. For reasons that aren't very clear to me, spammers are writting bots to randomly fill in forms and submit them, as if that will really boost sales of the advertised (and often misspelled) product.
I apologize in advance for the scattered and disorganized state of this entry. I wanted to say something about what I've been working on.
You can look at a working version of the solution described below here.
One solution I've see comes from Blogger, which can require users to type in the letters that appear in a image. The letters in the image are distorted and there is often some background noise. This is to throw off optical character recognition routines that spammers might imploy to figure out what letters appear in the image. The distortions and noise thwart most OCR attempts.
I like this approach, but since I'm not very good with image manipulation, I needed another way to do something similar. The answer came from some reading I did years ago when I wanted to make video games for a living. In particular, I recalled that console fonts stored in PC ROM where typical composed of 8x8 matrixes. I then thought that if I could recreate these matrixes, I could represent these patterns as alternating colors in an HTML table.
Of course, it wouldn't be especially hard to create routines that read in thees tables of characters and produce the original character, but that's a refinement for another day.
Once I could translate characters into an HTML table, it was an easy thing to create a random series of characters to feed to this routine. To prevent simple packet sniffing of the secret word, I needed a way to pass something back to the client that could be used to verify the word. Since sending the password in clear text was obviously a non-started, I needed some kind of hash. The most natural hashing algorithm to use for what amounts to passwords is DES, which has been used by UNIX systems to protect their authentication system for years (although it's not really as unbreakable as PKI schemes).
The next problem was to create a mechanism where an HTML page could request this bundle of HTML tables that represent a word. This is where the oft-talked about Ajax techniques come into play. Ajax is simple an asynchronous RPC mechanism that's built with javascript and some other server-side programming technology. It took me a good bit of time to work through the most common gotchas that prevent reliable transportation of the Ajax RPC messages. Popular browsers have different DOM parsers that treat large (> 4096 bytes) data differently.
There are two major problems with the approach described here. The first is that it would be easy to write an OCR routine to read the HTMLized font. The second problem is that anyone can bypass the security by creating there own DES hash of an arbritary string and passing that string in clear text to the ajax server.
Let me tackle the second problem first. To ensure that the hash-value recieved by the ajax server can be trusted, two methods can be used. The first is to rewrite the secret word checker to use a session-based system. The user would be passed a session ID from the server. The server would remember what secret phrase it sent to the user. The user sends back their guess in clear text. The validator retrieves the secret from a backing store and makes the check.
I don't much like this stateful solution, although I believe it is superior to the original implementation. If you've got an app that already has sessions, perhaps this is a natural fit.
Another solution to this problem is to use a Public Key Infrasture mechanism to encode the secret into a hexadecimal string. When the user returns this encoded secret along with the clear-text guess, the server decrypts the secret using a private key. If the encoded secret has been tampered with, the decryption will fail. I would recomend this solution as a refinement to the anti-spamming mechanism I've described.
The second and more difficult problem with my mechanism is that it would be
trivial to write OCR for the HTML emitted. It's true that the spam bot would
have to speak javascript to get to this data at all, since the HTML is
injected into the static web page via innerHTML(). But I don't
think that's sufficiently obscure enough to baffle spammers. What would be
needed is some kind of "noise" in the HTML to making OCR difficult. Other
than adding spacing, altering capitalization and adding weird HTML attributes,
there's nothing that a solid HTML parser and a good coder couldn't get a round.
All of this has made me appreciate just how good the human brain is at finding meaning in chaos. Digital creations just aren't up to that task yet.
Here's another boring programming note to myself. Please note that I had to break lines of code for formatting reasons. Please use this syntax as a guideline. Don't try to cut and paste it.
Ajax is all the rage now. To me, it's just web services done with Javascript and Javascript blows bigger chucks than Java (and we all know how I feel about that).
In playing with the simple code on Mozilla's site, I realized that the browser complicates using Ajax as a simple RPC mechanism. The reason? Browsers are inherently multithreaded applications and so all the RPC Ajax calls must be asynchronous. That means that you can't directly port something like XML-RPC or SOAP (both of which are more or less synchronous) to Ajax. Browsers run javascript on events. When the Ajax response finally comes back to the browser, a callback function is needed to continue processing the response.
That's not so bad, but what if you really want to do this:
<script>
var uid = ↵
RPCRequest('server.php?action=getUID?username=jjohn');
</script>
The problem is that RPCRequest returns as soon as the request is made, not when the response comes back.
Here's the typical Ajax code (via the Mozilla article) that makes the request and parses the response:
// file: ajax.js
// make the request, register the callback
function makeRequest(url, cb) {
var http_request = false;
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
http_request = new XMLHttpRequest();
if (http_request.overrideMimeType) {
http_request.overrideMimeType('text/xml');
}
} else if (window.ActiveXObject) { // IE
try {
http_request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
}
}
if (!http_request) {
alert("No HTTP object!");
return false;
}
http_request.onreadystatechange = function() {
alertContents(http_request, cb); };
http_request.open("GET", url, true);
http_request.send(null);
return http_request;
}
// the callback to handle the response from the server
function alertContents(http_request, cb) {
try {
if (http_request.readyState == 4) {
if (http_request.status == 200) {
// parse out response
var resp = http_request.responseXML;
var val = ↵
resp.getElementsByTagName("response"). ↵
item(0).firstChild.data;
cb(val);
} else {
alert('There was a problem with the request.');
}
}
} catch (e) {
alert("Exception: " + e.message);
}
}
In this code, I expect a rather meager XML response that has only a response tag.
I got the notion that what I should do with the response handler is send it a callback from the caller to handle the parsed response. Something like the following:
<!-- file: test.html -->
<html>
<head>
<script type="text/javascript"
language="JavaScript" src="ajax.js">
</head>
<body>
<span
style="cursor: pointer; text-decoration: underline"
onclick="makeRequest('server.php', ↵
function(x){ alert(x) })">Make a request</span>
</body>
</html>
Again, this works fine when the anonymous function has a globablly defined
function like alert(). But what if you want to define a function
in the caller's HTML page and have it called from code in the ajax.js page?
I haven't figured that out yet (but see below).
The problem is that the scope of functions defined on the calling page is not visible (it seems) to the functions in the ajax.js page. I think I could get around this using fully-qualified DOM names ore something nutty like that.
I want to use objects, but of course, Javascript has classless objects which don't help here. I guess I could define the callback behavior for each call, but that seems dumb.
I need to sleep on this a bit.
UPDATE: What a difference eight hours of sleep makes!
After digging around the javascript books I have, I came up with this more object-oriented version of the ajax code that removes the callback function in favor of a user-overridden method. That nicely divides that generic RPC tasks from the caller-specific ones. The code appears to run in both Firefox and Internet Explorer on my XP box, but I'm sure it will break in Opera and Safari.
Let's look at the new ajax.js file. This defines an "class"
call RPCClient.
/* Much of this is from
* http://developer.mozilla.org/en/docs/AJAX:Getting_Started
*/
function makeRPCRequest(url) {
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
this.http_request = new XMLHttpRequest();
if (this.http_request.overrideMimeType) {
this.http_request.overrideMimeType('text/xml');
}
} else if (window.ActiveXObject) { // IE
try {
this.http_request = ↵
new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
this.errstr = e.message;
}
}
if (!this.http_request) {
alert("No HTTP object!");
return false;
}
// Can't use 'this' in callback.
// Gets confuses with http_request.
var thisObj = this;
this.http_request.onreadystatechange = function() {
thisObj.watchResponse();
};
this.http_request.open("GET", url, true);
this.http_request.send(null);
}
function parseRPCResponse() {
try {
if (this.http_request.readyState == 4) {
if (this.http_request.status == 200) {
// parse out response
var resp = this.http_request.responseXML;
var val = ↵
resp.getElementsByTagName("response") ↵
.item(0).firstChild.data;
this.handler(val);
} else {
alert('There was a problem with the request.');
}
}
} catch (e) {
alert("Exception: " + e.message);
}
}
// define the RPCClient object
function RPCClient () {
this.errstr = false;
this.http_request = false;
}
// navigator 3 bug workaround for prototype
new RPCClient();
RPCClient.prototype.send = makeRPCRequest;
RPCClient.prototype.watchResponse = parseRPCResponse;
RPCClient.prototype.handler = function (x) ↵
{ alert("Default handler.n" + x) };
The idea of this code is that the user overrides the handler
method to do something useful with the value that comes back from server.
Most of this code just replaces procedural elements with OO mechanisms. However, notice this stupid looking assignment:
var thisObj = this;
I had to do this because of scoping behavior that, as a Perl coder, I find
nutty and wrong. The trouble comes when I want to use the current object in
the http_request callback/method onreadystatechange. Like most
method declarations, I use an anonymous function to override the default
action. When I try to use the this in the callback/method, it
then refers to http_request object, not the RPCClient object.
Ugh.
I guess JavaScript has to work this way, since it doesn't have proper
namespaces or Perl closure rules. How can I tell JavaScript which object
this refers to? The answer is not to use this, but
a reference to the current RPCClient object.
This is a pretty subtle point and it's easy to get forget. Of course, if you only use JavaScript, it probably makes perfect sense to you.
Time for the calling HTML page.
<!-- file: test.html -->
<html><head>
<script type="text/javascript" language="JavaScript1.2"
src="ajax.js"></script>
<style type="text/css">
.fakeURL { text-decoration: underline; cursor: pointer;}
</style>
<script type="text/javascript" language="JavaScript1.2">
var rpc = new RPCClient();
rpc.handler = function(x) { alert("From the caller: " + x)};
function dump (obj) {
document.write("<div><p><b>Object properties</b></p><dl>n");
for (var p in rpc) {
document.write("<dt>property: <code>" + p
+ "</code></dt>" + "<dd>type: <code>"
+ typeof(rpc[p]) + "</code></dd>n");
}
document.write("</dl></div>n");
}
</script>
</head>
<body>
<script type="text/javascript" language="JavaScript1.2">
//dump(rpc);
</script>
<span class="fakeURL"
onClick="rpc.send('ajax.php')">Make a request</span>
</body>
</html>
There's a bit of debugging code in there that dumps the properties of
the RPCClient object. I left that code here for future debugging needs.
A new RPCClient object is instantiated as you'd expect. The default
handler is overridden with a trival method.
Now the RPC mechanism looks a little cleaner! It's still asynchronous, but all the caller side code can be stored with the caller.
For the record, here's the PHP server, which is just echoes the values passed to it:
<?php
header("Content-Type: application/xml");
header("Cache-Control: no-cache");
print "<?xml version='1.0'?>";
?>
<response>
<? foreach($_GET as $k => $v) {
print "$k => $vn";
}
?>
</response>
This PHP is pretty trivial, but there are a few gotchas.
You have to set the MIME type correctly and disable browser caching.
You also have to emit XML, which is no big thing, except that the XML declaration looks like PHP code to PHP, so I had to be a little crafty in emitting it.
Finally, I just echo the key-value pairs I receive. Simple!
The next iteration of the code will pass the response back as a base64 encoded string. I don't need to pass complex data to the browser, but I may want to pass HTML. From my years of XML-RPC hacking, the best way to do this is by encoding the HTML. Otherwise, you'll go mad.
Have I mentioned that XML sucks too? It does.
Happy hackin'.
Recently, I had to wade deeper into the murky, fetid waters of JavaScript. Like an encounter with a cheap hooker, a session coding with JavaScript makes me want to shower and weep. What I had to struggle with on this occasion was JavaScript's notion of associative arrays, which are implemented as Objects. All you Perler, Pythons and Rubyists out there, hold on! It's not that associative arrays are a type of object in JavaScript, it's that Objects are associative arrays (have I BLOWN your MIND yet, Java?).
Normally languages which provide associative arrays also build in
routines to list the keys, the values or both from an instance of these
variables. Not JavaScript. It's true that you can iterate through an Object's
attributes with a for/in loop, but that's a bit like using a
hammer to repair a watch, which is an analogy that also holds for parsing
query strings in URLs with JS. What a nightmare. It's always 1996 in
JavaScript's world.
Weirded out yet? Wait! I've held the most offensive bit of JavaScript classes for last. In nearly every other God-fearing lanaguage I've used, Objects are declared. That is, the object's attributes and methods are defined (usually) before an instance of that class can be used. So JavaScript, whose name clings to the fame of that paragon of OO-design Java, should have some kind of class declaration, right? I mean, declaring a class would make inheritence and object inspection easier and thus leverage the the major benefit of Object Oriented (OO) programming, right? Therefore, JS must have class declarations. But sadly, this isn't the case. JavaScript sports Classless objects. Objects in JS are defined at run time procedurally, in what seems to be an attempt to make the brains of OO zealots melt.
Classes without an inheritence mechanism are like pants without bottoms and only David Lee Roth could get away with wearing assless pants.
How does JavaScript allow users to define their own classes? You make a generic Object and start assigning methods and attributes to it, as if it were a dictionary, which it really is! How does object inheritence work? Not very well, but you can try assigning to the pseudo-attribute .prototype. Or not. Apparently, prototype is sort of busted.
Another consequence of not having classes is that you can never find out
what kind of Object you're dealing. That is, you can't ask an object,
"what class do you belong to, little fella?" The confused bastard will
answer "I'm an Object Object," which sounds a little desperate -- like the
JS object really wants you to believe it's a first class object, which
it isn't. This reminds me of a common folklore tenet in which all things
have a Truename that, if uttered, will give the speaker power over that thing.
Are JS objects superstitious? It's true you can "override" (or overwrite)
the .toString method with something about the class name, but
that's hackiferic.
Anyway, why bother with class heirarchies? Most JS scripts last only a short while and have so limited a scope. Then again, why bother pretending to have objects at all? Let's call a hash "a hash" and be done with it.
Classless classes are the assless pants of the Internet.
About this blog
The taskboy blog is a exploration of computer technology by Joe Johnston. Topics of posts include practical examples Perl, PHP, Python and Java as well as book reviews, industry insights and miscellaneous good stuff.
Current Status
Watching _Brass Latern_. Ah IF, your coyness is your charm.
Posted: Sun Sep 05 16:02:15 +0000 2010
Latest Feedbag
- Need Niche Network Group Buying Deals? Meet ChompOn
- Q&A: Five key questions about midterm elections in Congress
- Grain Sack Doubles Up As A Water Purifier Kit
- BMW Takes Internet Car Reveals To A Weird New Level
- Monocolumn: Imelda Marcos, Mark 2
- Zoodles Brings Kid-Friendly Browser To Android Phones
- Context Optional Helps Brands Run Location-Based Promotions On Facebook Places
- Eric Schmidt: Were Already Fast..Fast Is About To Get Faster
- Coulomb Wins $15 Million To Roll Out Electric Vehicle Charging Stations Across America
- Ping Is Apples iTunes For Everything
Generated: 10:15 on 08/Sep/2010
Recent posts
- Very quick git primer for basic functionality
- Tips for spammers: don't insult me
- CakePHP vs. Symfony: a quick note
- Creating events for Yahoo and Google calendars
- SANs on a budget: iSCSI under Ubuntu
- iPad, iTouch and Kindle: Which is the better mousetrap?
- Rise of the Ad-Hocracy, Part II
- Rise of the Ad-Hocracy, Part I
- Small Hiatus
