|
YOUR FEEDBACK
Did you read today's front page stories & breaking news?
SYS-CON.TV
|
TOP THREE LINKS YOU MUST CLICK ON Real-World AJAX Book Preview AJAX Logging Functions
Because we want our JavaScript to be able to write to the log window in our HTML, we'll first add the logging code
By: James Benson; Jay Fienberg
May. 15, 2007 06:45 PM
This content is reprinted from Real-World AJAX: Secrets of the Masters published by SYS-CON Books. To order the entire book now along with companion DVDs for the special pre-order price, click here for more information. Aimed at everyone from enterprise developers to self-taught scripters, Real-World AJAX: Secrets of the Masters is the perfect book for anyone who wants to start developing AJAX applications.
Logging Functions As we described earlier in Listing 12.6:
Listing 12.11 Logging
var logDisplayLevel = 1; The code in Listing 12.11 allows us to write messages to the log window in our HTML. The key code are the last two lines of the log() function that use the Prototype library's Insertion.Bottom() to append new text at the bottom of the log window, and $() to set the log window's scroll position to the bottom. The log() function also checks against the global setting of log levels and the display level. This allows us to display more or less messages in the window. Throughout our JavaScript, we'll include a lot of debug and fewer info-level messages. The globals at top of Listing 12.11 define three log levels (debug, info, and error) in the logLevels array. And, the logDisplayLevel variable then represents a default/initial log level (i.e., it corresponds to the value at logLevels[1], which is "info"). We'll also set the HTML ID of the logWindow here--this allows us to easily switch to a different HTML element if we want to use a different design. Note here that there are a few interdependencies between the JavaScript and the HTML. These are:
The Initialization, Login and Logout Related Functions, Round 1 The first thing we do is log that the window has loaded; this is the first line in Listing 12.12.. Listing 12.12 on load
window.onload = function() { Besides our first log message, we set event listeners for the general interface features of login and logout, and the radio buttons in the log window. As we noted earlier, our HTML includes no inline JavaScript. And, specifically, for each of the Java Script triggers we need to be bound to the HTML, we instead define this binding in the JavaScript itself by using the Prototype library's Event.observe() function. Event.observe() is a convenient and altogether handy way to grab an element in the HTML (the first parameter), set a listener for a specific event type (the second parameter), and attach a function (the third parameter) that is called for that event. For example, our second line, Event.observe("user", "change", login, true), refers to the user dropdown (HTML select element) that we saw earlier in Listing 12.7. When that drop-down changes values (e.g., a username is selected), we'll call a function called login (explained in detail later). Note how we do not use a named function for window.onload, but instead use the window.onload = function() {} form. Since we know that the window will load only once, we don't need a name for our function as we won't be calling it again. Similarly, in the Event.observe() calls for the radio buttons, we use unnamed functions to set the logDisplay level and log the change. The last line of our window.onload function is to call a loadUsers() function - let's look at this next.
Load Users We'll use the Prototype library's Ajax.Update function to call our server's /userlist method. As we noted above (see Listing 12.10a), the server returns exactly the format we need - each user listed as an HTML <option>. Ajax.Updater is a good choice here because, as soon as it receives the results from the server, it immediately writes the results into the HTML element of our choice (our <select id="user"> in this case). Listing 12.13a Load Users
var baseURL = 'im.php'; Here's what our IM client looks like with the users loaded.
Login and Initialize Along with these, we'll also define some global variables whose values will be reset with each login. Our initialize() and login() functions will then begin assigning values and objects to these variables, as well as update the user interface to reflect the logged-in state. Note that user name is stored in activeUser, and that this value comes from the HTML <select id="user"> that we just populated in Listing 12.13a. Listing 12.13b Login and Initialize
var ChatWindow = Class.create(); The login() function is bound to the change event of <select id="user"> (see Listing 12.12), and so the JavaScript keyword, in this case, refers to <select id="user">. We are able to get the value of the user name by first getting the index of the selected option (this.options.selectedIndex) and then using it to get the value of that option (this.options[idx].value). The login() function also updates the user interface to show the current logged-in user, hides the login control, and displays the logout control, and also resets the login control to its first option. Finally, login() creates a new Buddies() object (see Listing 12.16-22 for more details), stores it in the buddyMgr variable, and then calls a refresh() function (see Listing 12.33).
Logout Listing 12.14 Logout
function logout() { Global Variables We've introduced a number of global variables in the preceeding examples. We'll consolidate them all and place them at the top of our im.js file. Note that we've added a refreshInterval variable that we'll soon use in our refresh() function (see Listing 12.33). This variable will be used to set how often our IM client will poll the server for new data. By placing the variable here at the top, we'll keep it handy in case we want to adjust the value to make updates more or less frequent. We've also added a responseFormat variable that we'll use in all of our URLs to indicate the response format the server should return (in this case, HTML, e.g., to create a server request in the form of im.php/xml/John/buddies (see Listing 12.10d). While our IM client code will not directly work with others if you change the reponseFormat to XML or JSON, we included this as a variable to suggest that, as an experiment (left as an excercise for the reader, as the old textbooks used to say) one could extend the code to handle the different response types, and then could switch between them by changing this value. Listing 12.15 Global Variables
[EXAMPLE 15: global variables]
Basic Process Flow of the IM Client First, we load the users. This gives us a list of user names we can select from. We select a user name to log us in. Logging in does three things:
Finally, logging out will return the application to the ready for login state.
Buddies and Chat Window Objects Classes are defined in JavaScript as prototypes, which have a syntax that looks something like creating a variable and assigning it a value. But, instead of assigning it a value, we assign it what can generically be called methods (functions) and properties (variables). Listing 12.16 provides a skeleton example using this syntax. Listing 12.16 Creating Classes
ClassName.prototype = {
Buddies Object The Prototype library extends the basic JavaScript class and defines an intitialize() function that is automatically called at the time of object creation (not unlike the init() method common in Java classes). We'll take advantage of this and use initialize() to set up our Buddies object. Initialize Listing 12.17 Initialize
Buddies.prototype = { In our intitialize() function, we define a number of properties (instance variables) by using this keyword in front of variable names. Each object created from this class will include these properties, and these properties will have their values set at the time of creation by our initialize() function. First, we define the listWindow to be the HTML element that will contain the buddy list. We then set its CSS display style to "block" to make it visible. We also define the statusControl to be the HTML element that allows the user to change their status. This is the <select id="status"> element, which we also set to display the first option. Next, we set the user's status by calling the Buddies object postStatusUpdate() function that we'll describe in Listing 12.21. What we're doing here is encapsulating all of the status-changing features in the Buddies object. This particular status change is a consequence of the user logging in, e.g., when the user logs in, his status becomes "Available". But, because all of the other status changes are triggered within the Buddy List context (i.e., because we designed the status change control to be part of the Buddy List display), we trigger this status change at this point rather than earlier in the login process. Finally, we add an Event observer on the status control to catch when the user uses it to change his status. Although this is functionally almost the same as using Prototype's Event.observe() function, we have to do a little trick to reconcile the "this" keyword between the Event's this and our Buddies object's this. By default (and, as we described earlier in Listing 12.13b), Events are bound to the HTML element. This means that, in the function called by the Event, "this" refers to the HTML element. This information is all one needs when not working in an object-oriented manner because, generally, all of the data and functions that are needed are available globally in the JavaScript. When working in an object-oriented manner, data and functions become encapsulated inside objects, and so are not available with reference to the specific object variable that contains the object. In our case, we want the Event to call a method inside of an instance of an object. We need the "this" keyword to refer to that object instance. Fortunately, Prototype allows us to add bindAsEventListener(this) to our Event objects to bind the Event to our Buddies object rather than to the HTML element. And, so we create a new Event object like this: this.changeStatusObserver = this.changeStatus.bindAsEventListener(this); And, bind the Event object to the HTML object like this: Event.observe('status', 'change', this.changeStatusObserver, true); We'll be using this technique throughout our classes to cause Events to trigger methods within specific object instances of the class. This content is reprinted from Real-World AJAX: Secrets of the Masters published by SYS-CON Books. To order the entire book now along with companion DVDs, click here to order. LATEST AJAXWORLD RIA STORIES
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
|
SYS-CON FEATURED WHITEPAPERS MOST READ THIS WEEK |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||