GENE SIMMONS WOULD BE PROUD

Một phần của tài liệu Tài liệu Practical DWR 2 Projects pptx (Trang 168 - 173)

The KISS principle, as opposed to the rock band (which would probably notbe described by this principle), is an acronym for Keep It Simple Stupid (other oft-sited definitions include Keep It Simple Sherlock, Keep It Sweet & Simple, and Keep It Short & Simple). It is a common phrase used in software engineering (and in other engineering disciples in general) that basically means to not overthink a problem.

It is oftentimes a given that engineers and creative thinkers tend to come up with solutions to problems that are more exercises in their own ability to think “outside the box” than in solving the problem in a practi- cal, simple manner. Java developers in particular, for whatever reason that my C final grade in Psychology class doesn’t qualify me to determine, tend to do this frequently (especially, but not exclusively, those with any variation of the word “Enterprise” in the job titles!). This frequently leads to solutions that are brittle because they have more moving parts than is necessary, and which are also difficult to maintain later.

The KISS principle is roughly equivalent to the famous Occam’s Razor principle, which states (as uttered concisely by Jodi Foster’s character Dr. Ellie Arroway in the movie Contact) “. . .that, all things being equal, the simplest answer is usually the right one.” Albert Einstein also said it extremely well (you wouldn’t expect him to say something poorly, would you?) when he said that “Everything should be made as simple as possi- ble, but no simpler.”

It may not be the principle of choice for those who charge consulting fees by the hour, or who make a living writing research papers all day long, but for those of us who work to develop solid, maintainable, and extensible business software each and every day on time and under budget, it’s one of the best guiding lights you can have.

After that comes the markup for InstaMail in its entirety. Notice as you use the application that there are a number of views, a.k.a. screens, that you can flip between. Notice too that as you do so, you are never retrieving the page from the server. From the start, all the various views of the application are in your browser. Each view is its own <div>on the page, and the appropriate <div>is shown at the appropriate time. There is the Intro <div>, the Inbox <div>, the Sent Messages <div>, the Message <div>, the Address Book <div>, the Options <div>, and the Compose <div>. Looking through the contents of index.jsp, you will literally see those

<div>s. This seemingly simple structure yields a great deal of power and makes for a very well- performing application. Think about it: the server only returns data to us; all of the markup is already on the client. This is very bandwidth efficient, and yields fewer delays in switching views for the user. Something like clicking the Compose button is instantaneous. Even a small delay here, as would be present in a typical webapp where the server would be called upon to serve that page, would be perceived by the user in a negative way. This approach completely avoids that problem.

One thing I would like you to notice as you look through the markup is how few times you see the styleattribute used on elements. Except for a few exceptions, only classis used. This is by design. The presentation has been abstracted out into the style sheet almost entirely (and truthfully it could have been abstracted out entirely). Doing this cleanly separates what your application looks like from its structure, as we have discussed before. Even this application, however, does not go as far as is possible in this regard, but it does go further than some of the other applications in this book do.

Aside from these few points, the markup is actually rather unremarkable. I therefore leave it to you to examine in your own time. I believe you will find that there is really very little going on. What you will see, though, is a lot of calls to JavaScript functions that exist in script.js, and that is therefore our next destination.

script.js

script.js, being another very long piece of code, won’t be listed completely here either. I’ll again call out the pieces that are pertinent, as the discussion warrants. But also like before, I suggest taking a moment now to get the “lay of the land,” so to speak, by having a look at the entire source file yourself. When you’re all done, come back ’round these parts, and we’ll start tearing it apart together.

Setting the Table for Efficiency

The first thing you see in this file is a batch of image preloads, all looking like this:

img_send = new Image();

img_send.src = "img/send.gif";

img_send_over = new Image();

img_send_over.src = "img/send_over.gif";

There are of course a lot more of them (11 in total), but they all take this same basic form.

An image preload is nothing but some JavaScript that loads an image from the server into the browser’s memory. This is usually done for image rollovers, that is, when an image changes when you move your mouse over it. The preload stops the browser from having to go out to the server when your mouse moves over the image to get the alternate version. If it did this, the user would perceive a delay, which is unpleasant. This example shows preloading the two versions of the Send button: how the button looks when you are not hovering over it, and how it looks when you are.

A Few Globals Never Hurt Anyone

Following that are three global variables, described in Table 4-2.

Table 4-2.Global Variables in script.js Global Variable Description

currentView This stores the name of the current view, that is, the name of the <div>that is currently visible.

checkboxNumber Later on in the code, we’ll be dynamically populating a table, and next to each item in the table will be a check box. Each check box needs to have a unique ID associated with it, and to do this we simply attach a number onto the end of its name. This variable is used during that process. With the way the table creation is done using DWR, making this variable global seems to be the only way to persist its value across function calls, which is what we need to do to make this work.

appConfigured This is set during initialization, and it is used later on when a determination about the app being configured or not is required in the JavaScript.

Next up we see two functions that handle our mouse events for our buttons on the top and side:

// onMouseOver handler for buttons.

function btnMouseOver(obj) { id = obj.id;

obj.src = eval("img_" + id + "_over").src;

obj.style.cursor = "pointer";

}

// onMouseOut handler for buttons.

function btnMouseOut(obj) { id = obj.id;

obj.src = eval("img_" + id).src;

obj.style.cursor = "";

}

This is pretty typical mouse rollover code. We get the ID of the object that called the method, one of the buttons, and then use the eval()function to get a reference to the appro- priate preloaded image. We then set the srcof the button to the srcof the preloaded image, completing the rollover (or rollout, as it were). In addition, the cursorstyle attribute is changed so that we get a pointer when we hover over a button.

Make the Mouse Do Pretty Things

After that are two similar functions for dealing with rows in either the Inbox or Sent Messages tables:

// onMouseOver handler for rows in Inbox or Sent Messages.

function rowMouseOver() {

this.parentNode.className = "rowHover";

}

// onMouseOut handler for rows in Inbox or Sent Messages.

function rowMouseOut() {

this.parentNode.className = this.parentNode.rowClass;

}

You may be wondering about that rowClassattribute. There’s no such attribute in HTML!

It is in fact a custom attribute that’s used to store the class of the row that a cell uses. In DOM scripting, you can add attributes at will to nodes, or to HTML tags, which of course are them- selves DOM nodes. This comes in very handy when you need to store bits of metadata about a node, as is the case here.

Contrast the two event handler versions, meaning look at the event handlers for the but- tons vs. the handlers for the rows, and you will see they are a bit different. Part of it is that they had to be different, and part of it is that I wanted them to be for the sake of seeing two approaches. First, let’s discuss why they had to be different . . . as you can see in Figures 4-3 and 4-4, the Inbox and Sent Messages views contain a table listing messages that you can click to view the message. The contents of these tables are generated dynamically. Part of that gen- eration is attaching event handlers to the cells in the table. As a preview, look at this snippet:

td1 = document.createElement("td");

td1.onmouseover = rowmouseover;

Figure 4-3.The InstaMail Inbox view

Figure 4-4.The InstaMail Sent Messages view

The first line should be obvious: it is asking the document object to create a new <td>ele- ment for us. Note that this element does not immediately become part of the DOM. Instead, it’s simply created and returned to the caller. The second line attaches an event handler to the onMouseOverevent. Recall that in Javascript, functions are true objects. What we’re in effect doing here is setting the onMouseOverproperty of the new <td>element to the rowMouseOver object, which just so happens to be a function. Note the syntax, though: there is no parameter list given when doing this. The fact is that it’s not possible to pass parameters to a handler when you set it on an object like this. Therefore, unlike the button handlers, we could not pass the thisreference to it.

Fortunately for us, thethisreference is intrinsic when you attach an object to another in this manner. Recall how prototyping works in JavaScript (or read the “Prototype-Based Languages”

sidebar if you’re not sure) and this should make sense. The onMouseOverproperty is now an object reference, which for all intents and purposes becomes a part of the object it is attached to, the <td>in this case. So, within this function, thishas meaning.

Một phần của tài liệu Tài liệu Practical DWR 2 Projects pptx (Trang 168 - 173)

Tải bản đầy đủ (PDF)

(570 trang)