Saturday, August 15, 2009

Red Alert!

Here's a tidbit we used in the jQuery and ColdFusion class. You can write your own functions to replace JavaScript functions. The example for this involved writing an alert() function that displays error messages in a nice jQuery-created popup div instead of the ugly old JavaScript alert box. When applied, alerts (including those thrown by ColdFusion-generated validation JavaScript) look like this:


Of course, you can style the message any way you like--it's just in the CSS. As with all class examples, this is intended as a launching point for your exploration, rather than a finished tool ready for production. Here's the code; we'll go through line by line tomorrow.

<html>
<head>
<title>Javascript Alert Test</title>
<script type="text/javascript" src="../jquery/jquery.js"></script>
<style type="text/css">
#msgDiv {
height: auto;
width: 200px;
font-family: Tahoma, Helvetica, sans-serif;
font-size: 80%;
text-align: center;
background-color: #FFAAAA;
border: 1px solid red;
position: absolute;
top: 60px;
left: 50%;
margin-left: -100px;
}
#msgHeader {
background-color: red;
color: white;
font-weight: bold;
}
#msgText {
padding: 5px;
}
</style>
</head>
<body onLoad="alert('Hah!');">
<h2>CFFORM with Custom Alert</h2>
<cfform name="myForm" action="" method="post">
Full Name: <cfinput type="text" name="fullName" id="fullName" required="Yes" message="Enter your full name." /><br />
Email: <cfinput type="text" name="email" id="email" validate="email" required="yes" message="Enter your valid email address." /><br />
<cfinput type="submit" name="btnRegister" value="register" />
</cfform>
<script type="text/javascript">
function alert(msg){
if(title == undefined){
title = 'foo';
}
msgText = '';
if (msg.typeOf = "Array"){
for (i=0; i<msg.length;i++){
if (msg[i] == String.fromCharCode(10)){
msgText += '<br />';
} else {
msgText += msg[i];
}
}
} else {
msgText = msg;
}
alertHTML = '<div id="msgDiv"><div id="msgHeader">Error:</div><div id="msgText"</div></div>';
$("body").append(alertHTML);
$("#msgDiv").hide().fadeIn();
$('#msgText').html(msgText + '<br /><input type="button" value="OK">')
$('#msgDiv').click(function(){
$(this).remove();
});
}
</script>
</body>
</html>

Tuesday, August 11, 2009

A Good Time Was Had By All--

Today was the "jQuery and ColdFusion" class I taught as part of the offerings for CFUnited '09. I have to say the class was a great success, mostly because of the great bunch of students we had. Everyone who was there came with great curiosity and readiness to participate and discuss, so the day really flew by.

So my little post today is just a few sites we included in bookmarks for the class--from the jQuery site itself to some other nifty places to visit if you're jQuery-minded. I hope you get something out of them.

Have fun!

Friday, August 7, 2009

Class Prep Weekend

Not a whole lot going on today. I'm mostly spending time getting ready for the class I'm teaching on Tuesday: "jQuery and ColdFusion". Just a few last-minute things to wrap up before it's "show time". I think I'll take the weekend off from blogging, so Monday we'll meet again.

Have fun!

Thursday, August 6, 2009

Tooltips for Links Deconstructed

Yesterday's post introduced a way to add tooltips to links. Now let's go over the code and see how everything works. First, the HTML. It's very basic--just an unordered list and a couple of paragraphs of text, one of which has a link within its text. But we'll go through it just to make sure everyone's on board.

First off, the usual HTML and HEAD elements:

<html>
<head>


Then we have the lines that make jQuery, a jQuery plugin for drop shadows, the JavaScript file for this page, and the CSS file for this page available:

<script type="text/javascript" src="/jquery/jquery.js"></script>
<script type="text/javascript" src="/jquery/jquery.dropshadow.js"></script>
<script type="text/javascript" src="jqTooltips.js"></script>
<link type="text/css" rel="stylesheet" href="jqTooltips.css" />


And we close the head and the body:

</head>
<body>


Now an H1 element with the page's title:

<h1>jQuery Tooltips for Links</h1>


And a paragraph to describe what we're doing:

<p>This page shows how some simple jQuery code can set up popup tool tips for links. The premise is that this page will be used by web neophytes who might need some help to understand how everything works. So let's have a few links:</p>


Now we set up an unordered list that has a link in each list item:

<ul>
<li><a id="lnkProtonArts" href="http://www.protonarts.com">Proton Arts</a></li>
<li><a id="lnkThejQueryWebsite" href="http://www.jquery.com">The jQuery Website</a></li>
</ul>


Notice that there's nothing extra going on in the link tags--they're just plain old links. I have set and id attribute in each one, just to make them easier to identify. More on this when we get to the JavaScript file.

Next, just another paragraph with another link inside it. This is included just to show that any A tag added to the page will automatically get the same treatment. Try it--add your own links to the HTML and see what happens:

<p>Of course, if we just insert a stealthier link to <a href="http://www.youtube.com">YouTube</a> within some paragraph text, jQuery picks up on that one, too.</p>


And finally, the closing tags for the BODY and HTML:

</body>
</html>


Now let's get to the CSS, since it's not very inspiring... It's in the jqTooltips.css file.

We use the BODY element to set up the font family for the entire page.
body{
font-family: Verdana, Helvetica, sans-serif;
}


Then we use the tooltip class to style our little tips. Notice there is no width or positioning information--it's created in the HTML by the JavaScript code.

.tooltip{
padding: 5px 0px 0px 5px;
background-color: yellow;
height: 25px;
font-size: 75%;
font-weight: bold;
text-align: center;
border: 1px solid black;
}


Now for the real fun: the JavaScript. It's in the jqTooltips.js file. The first thing we do is build a couple of functions: one to create a tooltip and one to destroy a tooltip. I've added comments to the code to explain it:

function makeATooltip(atag){ //The function call includes the variable atag, which is a jQuery return set containing an A tag.
tipTop = atag.offset().top - 20; //We calculate the top position of the tool tip by adding 20 to the top of the A tag.
tipTop += "px"; //Now we append "px;" to the end of the tipTop variable.
tipLeft = atag.offset().left + 30; //We use the same technique to calculate the left position for the tooltip.
tipLeft += "px";
tipText = "Click on this link to visit ";
tipText += atag.text(); //The text that appears in the tooltip includes the text from inside the A tag.
tipText += ".";
tipWidth = tipText.length * 7 + "px"; //We use the length of the tip's text to calculate the width of the tooltip.
tipHTML = "<div class='tooltip' id='"; //And now we can build the HTML that describes the tooltip.
tipHTML += atag.attr("id"); //We use the A tag's id attribute to assign an ID to its tooltip.
tipHTML += "Tip' ";
tipHTML += "style='{position: absolute;; "; //The tooltip's position is specified on the fly.
tipHTML += "top: " + tipTop + ";; ";
tipHTML += "left: " + tipLeft + ";; ";
tipHTML += "width: " + tipWidth;
tipHTML += "}'>"
tipHTML += tipText
tipHTML += "</div>"
atag.after(tipHTML); //The HTML is injected as a new element after the A tag.
$("#" + atag.attr("id") + "Tip").dropShadow(); //And we use jQuery to add a pretty drop shadow.
}

function destroyTooltip(linkID){ //The function call includes the variable linkID, which is a string.
$("#" + linkID + "Tip").removeShadow().remove(); //We use jQuery to remove the shadow first, then remove the tooltip.
}

$(document).ready(function(){ //The ready method of the document element specifies a function to run after page load.
$("a").hover(function(){ //The hover method is assigned to all A elements. It has two arguments:
makeATooltip($(this)); // the first is called on mouseover
}, function(){
destroyTooltip($(this).attr("id")); // the second is called on mouseout
});
})

That's all there is to it. As usual, we can do quite a bit with just a little bit of jQuery-based code. The important points to take away from this exercise are: 1. You can use jQuery to extract information from page elements and customize added elements, like we did with the text in each tooltip; 2. Positioning of elements relative to existing elements is simple with jQuery; and 3. Plugins such as Dropshadow make it extremely easy to add professional polish to your jQuery-based applications.

Have fun!

Wednesday, August 5, 2009

Tooltips for Links

Today's tinkertoy explores how jQuery can provide enhanced interface experiences with very little code. It adds a popup tooltip to every link (<a> tag) on the page.
Now, there are plenty of jQuery plugins for doing tooltips. Please don't think my little effort is presented as a production-ready alternative to them; it's not. It's just a way to get you thinking about how jQuery can do very cool stuff for your users without causing you to write a ton of code.
That said, here's a screen shot of today's experiment in action:

Here's the code, as HTML, JavaScript, and CSS. Tomorrow we'll step through it.

<html>
<head>
<script type="text/javascript" src="/jquery/jquery.js"></script>
<script type="text/javascript" src="/jquery/jquery.dropshadow.js"></script>
<script type="text/javascript" src="jqTooltips.js"></script>
<link type="text/css" rel="stylesheet" href="jqTooltips.css">
</head>
<body>
<h1>jQuery Tooltips for Links</h1>
<p>This page shows how some simple jQuery code can set up popup tool tips for links. The premise is that this page will be used by web neophytes who might need some help to understand how everything works. So let's have a few links:

<ul>
<li><a id="lnkProtonArts" href="http://www.protonarts.com">Proton Arts</a></li>
<li><a id="lnkThejQueryWebsite" href="http://www.jquery.com">The jQuery Website</a></li>
</ul>

<p>Of course, if we just insert a stealthier link to <a href="http://www.youtube.com">YouTube</a> within some paragraph text, jQuery picks up on that one, too.</p>
</body>
</html>

JavaScript:


function makeATooltip(atag){
tipTop = atag.offset().top - 20;
tipTop += "px";
tipLeft = atag.offset().left + 30;
tipLeft += "px";
tipText = "Click on this link to visit " + atag.text() + ".";
tipWidth = tipText.length * 7 + "px";
tipHTML = "<div class='tooltip' id='";
tipHTML += atag.attr("id");
tipHTML += "Tip' ";
tipHTML += "style='{position: absolute;; ";
tipHTML += "top: " + tipTop + ";; ";
tipHTML += "left: " + tipLeft + ";; ";
tipHTML += "width: " + tipWidth;
tipHTML += "}'>"
tipHTML += tipText
tipHTML += "</div>"
atag.after(tipHTML);
$("#" + atag.attr("id") + "Tip").dropShadow();
}

function destroyTooltip(linkID){
$("#" + linkID + "Tip").removeShadow().remove();
}

$(document).ready(function(){
$("a").hover(function(){
makeATooltip($(this));
}, function(){
destroyTooltip($(this).attr("id"));
});
})


CSS:

body{
font-family: Verdana, Helvetica, sans-serif;
}

.tooltip{
padding: 5px 0px 0px 5px;
background-color: yellow;
height: 25px;
font-family: Verdana, Helvetica, sans-serif;
font-size: 75%;
font-weight: bold;
text-align: center;
border: 1px solid black;
}

See you tomorrow!

Tuesday, August 4, 2009

Back (I Hope) on a More Regular Basis

To update, here's what's been happening in Jeffworld: So far this year, my wife and I have bought a new house, moved out of our old house, moved into the new house, helped her parents move out of their house and get it sold, renovated our old house, and now sold it as well. All while doing the usual work, teaching, conference prep, and helping my daughter with an Algebra II online class.

Fortunately, all that's behind us now (OK, one more week of algebra, but hey...), so I'm trying to refocus on things that I'd like to keep up with. That said, blogging is one of them.

I've tried to be a daily blogger in the past, and I never seem to do very well. So I'm going to try a different approach here on jQNaB. Instead of cooking up a big example for every post, I'm going to see if I can just post a little something every day. Nothing big--at least not every day--but something regularly. Hopefully that will help keep things a bit more lively around here, and you won't be nearly as bored with me.

So, on we go. For today's jQuery-related stuff, just a reminder that I'm going to be teaching that class next week, the day before the CFUnited conference begins (a week from today, in fact). I'm really looking forward to it, and may use some of my class examples for future posts here. If you're interested, I think there might still be room. Go over to www.CFUnited.com and look under "Classes".

And for tomorrow: a little piece of jQuery to make instant tool tips out of links. That should be fun and not too complex.

Tuesday, July 7, 2009

Live and In Person

Ah, well--my record for regular blogging holds up yet again. As always, I tend to get distracted from blogs as my attention is taken by "real life". This is not a good thing for y'all, but there it is.

The good news is that there is an opportunity coming up real soon to spend a whole day playing with jQuery nuts and bolts. I'm going to be teaching a pre-conference class for the CFUnited conference next month. The class is scheduled for August 11th. It's about jQuery and ColdFusion and how to make them work and play well together. Details are at http://www.cfunited.com.

So why should you attend? Let my bad example with this blog be your guide. I tend to focus much less on something of interest unless I take the time to focus on it completely. Making a day to focus on nothing but jQuery and front-end "magic" might be just the thing you need to step up to the next level in your development skills. If you're interested, please head over to the site right away. Space is limited, and it would be unfortunate if you got there after the class filled up.

Also, employers are often willing to pay for registration at courses like this, particularly if it will provide immediate benefit for your work. Go ahead and ask--maybe you'll get to go at their expense. Oh, and if your company needs to know something about your instructor, you can show 'em my publication list at ProtonArts.com or Amazon.com.

If you do decide to go, let me know. I'll look forward to seeing you there!

Monday, February 23, 2009

Simple Calculator Deconstructed

Here's the deconstruction of the
calculator project, starting with the HTML:


<html>
<head>
<title>jQuery Calculator</title>
<link type="text/css" rel="stylesheet" href="calc.css"/>

<scripttype="text/javascript" src="/jquery/jquery.js"></script>
<script type="text/javascript" src="calc.js"></script>
</head>
<body>
<h1>jQuery Calculator</h1>
<tableid="calculator">
<tr>
<td colspan="4" id="display">&nbsp;</td>
</tr>
<tr>
<td class="btnOp">+</td>

<td class="btnOp">-</td>
<td class="btnOp">*</td>
<td class="btnOp">/</td>
</tr>
<tr>
<td class="btnNum">7</td>
<td class="btnNum">8</td>
<td class="btnNum">9</td>
<td class="btnMem" id="memClear">MC</td>
</tr>
<tr>
<td class="btnNum">4</td>
<td class="btnNum">5</td>
<td class="btnNum">6</td>
<td class="btnMem" id="memPlus">M+</td>
</tr>
<tr>
<td class="btnNum">1</td>
<td class="btnNum">2</td>
<td class="btnNum">3</td>
<td class="btnMem" id="memRecall">MR</td>
</tr>
<tr>
<td class="btnNum">0</td>
<td class="btnNum">.</td>
<td class="btnFunc" id="clear">C</td>
<td class="btnEq" id="equals">=</td>
</tr>
<tr><td colspan="4"><div id="tape"></div></td></tr>
</table>
</body>
</html>


This is very straightforward stuff.
Notice the lack of anything beyond basic HTML here—the idea is to
keep it simple and clean. Our rule is HTML = content (nouns), CSS =
appearance (adjectives), and JavaScript = behavior (verbs). So the
HTML sets up the nouns—a calculator table with number buttons,
operator buttons, function buttons, memory buttons, and an equals
button; and a “tape” div to display the journal.


This HTML, if rendered without CSS,
isn't very pretty. It looks like this:






So, we need to dress it up a bit—time
for the CSS. The CSS code contained in the project's stylesheet
looks like this:


body{
text-align: center;
font-family: Verdana, Helvetica, sans-serif;
font-size: 1em;
}
h1{
font-size: 100%;
}
table{
border: 1px solid black;
}
#display {
border: 1px solid black;
height: 30px;
color: blue;
font: Courier New, Courier, fixed;
text-align: right;
}
.button{
font-weight: bold;
height: 30px;
width: 30px;
text-align: center;
vertical-align: center;
}
.btnNum{

background-color: silver;
}
.btnFunc {

background-color: blue;
color: white;
}
.btnMem
{

background-color: blue;
color: white;
}
.btnMemFull{

background-color: green;
}
.btnOp{

background-color: blue;
color: white;
}
.btnEq{

background-color: maroon;
color: white;
}
#tape{
width: 200px;
height:auto;
border: 1px solid black;
color: black;
font: Courier New, Courier, fixed;
text-align: right;
}


All we're doing here is setting up
borders, fonts and colors for the various parts of the calculator. A
couple of classes to note in particular are the btnMemFull
class and the button class. They aren't referenced anywhere
in the HTML. These are classes that will be used by the JavaScript
via jQuery.


If we render the HTML with just the CSS
activated, it looks better than before, but not quite complete.
Notice the text on the buttons isn't centered, the buttons aren't
uniform, and the calculator isn't centered on the page.



These details will be picked up by the
JavaScript, by applying an attribute to the table and the button
class to all the buttons. We'll see that in a minute. First let's
take a look at all the JavaScript for the project:


var buffer = "0";
var expr = "0";
varmem = 0;
function appendBuffer(s){
buffer = buffer == "0" ? "" : buffer;
buffer += s;
}
function clearBuffer(){ buffer = "0"; }
function appendExpression(s){ expr += s; sd}
function clearExpression(){ expr = ""; }
function showBuffer(){ $("#display").html(buffer); }
function appendToTape(s){

$("#tape").append(s).append("<br />");

$(document).ready(function(){
$(".btnNum,.btnFunc,.btnMem,.btnMemFull,.btnOp,.btnEq").addClass("button");
$("#calculator").attr("align","center");
showBuffer();

$(".btnNum").click(function(){
appendBuffer($(this).text());
appendExpression($(this).text());
showBuffer();
});

$("#clear").click(function(){
clearBuffer();
clearExpression();
showBuffer();
});

$(".btnOp").click(function(){
if(expr > ""){

$("#equals").click();
}

appendExpression($(this).text());
clearBuffer();
});

$("#equals").click(function(){
appendToTape(expr);
buffer = eval(expr);
expr = buffer;
showBuffer();
});

$("#memPlus").click(function(){
mem += buffer * 1;

$(".btnMem").addClass("btnMemFull");
});

$("#memRecall").click(function(){
buffer = mem;

appendExpression(mem);
showBuffer();
});

$("#memClear").click(function(){
mem = 0;

$(".btnMem").removeClass("btnMemFull");
});
});

That's all there is to it—a
completely functional calculator. So let's step through the
JavaScript and see what's going on in there. First, we set up three
variables to store global values for the buffer (to be displayed),
the expression (to be calculated), and the memory value (used when
any of the M buttons is clicked):


var buffer = "0";
var expr = "0";
var mem = 0;


Next we set up six functions that will
be used later in the processing. They allow us to manipulate the
buffer, the expression, and the value in the tape div. These
are placed in separate functions instead of button-bound functions
because we want to be able to use these functions from several
different places in the application, as we'll see when we start
looking at the button-bound code.


Now we get into the code that is run
when the document loads, as indicated by the $(document).ready()
construct. Just as a reminder, this is the way jQuery allows us to
specify code that will be fun after the document has successfully
loaded into the browser. The first three lines define actions that
will take place right away. The button class is applied to every
member of the classes that define various types of buttons, then the
calculator table is aligned in the window, and the value of the
buffer variable is displayed in the calculator's display window:


$(".btnNum,.btnFunc,.btnMem,.btnMemFull,.btnOp,.btnEq").addClass("button");
$("#calculator").attr("align","center");
showBuffer();

Rendering with the JavaScript activated
shows that the calculator has taken on its final appearance as a
result of those three lines:



So that's much better. Everything is
aligned where we want it, and the buttons are all nice and uniform,
with their appropriate sizes and fonts.


Now we need a few functions to handle
the non-button-specific work of the calculator. We need a way to add
values to the buffer (for display):


function appendBuffer(s){
buffer = buffer == "0" ? "" : buffer;
buffer += s;
}

This function says, “if the value of
buffer equals zero, set the buffer to an empty string; otherwise
leave its value as it was. Then append the string passed into the
function to the buffer.” The ternary operation in the first line
gets rid of the zero when a number is appended at the beginning of a
calcuation.

We also need a way to clear the buffer.
We want the calculator to display zero when it's not busy, so the
function just replaces the buffer value with zero:


function clearBuffer(){ buffer = "0"; }


Similarly, we need functions to handle
appending to and clearing the expression. The expression is similar
to the buffer, except that it also handles the operators that are
clicked. Operators do not get displayed in the calculator's window.


function appendExpression(s){ expr += s; }
function clearExpression(){ expr = ""; }


Speaking of the calculator's window,
here's the function that displays the contents of the buffer in that
window:


function showBuffer(){ $("#display").html(buffer); }


This says, “Use the jQuery html()
method to replace the HTML inside the element whose id is 'display'
with the contents of the buffer.”


And we need a way to print out lines in the journal (or “tape”) as well:

function appendToTape(s){
$("#tape").append(s).append("<br/>");
}


This line says, “Use the jQuery append() method to add the string that is passed to me to the HTML inside the element whose id is 'tape'. Then use the same method to append a line break tag to the same element.”


The rest of the JavaScript assigns
various functions to the click event of the buttons on the
calculator. Let's take a look a them in sections and see what's
going on.


The first section is composed of four
functions which establish the basic functioning of the calculator.
First, we have a function that controls the behavior of each of the
number buttons:



$(".btnNum").click(function(){



appendBuffer($(this).text());



appendExpression($(this).text());



showBuffer();


});


This just says, “When I am clicked,
my text (number) is appended to the buffer and the expression using
the appendBuffer() and appendExpression() functions, and the buffer
is shown in the display using the showBuffer() function.”


We then have a function that controls
what happens when the “C” button is clicked:



$("#clear").click(function(){
clearBuffer();
clearExpression();
showBuffer();
});

This says, “When I am clicked, run
the clearBuffer() and clearExpression() functions to empty the buffer
and expression, and show the buffer in the display using the
showBuffer() function.”


Then we have a function that controls
the behavior of each of the operator buttons:


$(".btnOp").click(function(){
if(expr > ""){

$("#equals").click();
}

appendExpression($(this).text());
clearBuffer();
});

This says, “When I am clicked, if
there is something in the expression then click the Equals button.
Then use the appendExpression() function to add my text (operator) to
the expression, and use the clearBuffer() function to empty the
buffer.” Using this approach allows us to add operators to the
expression without showing them in the display (buffer).


Finally, we have a function that
controls what happens when the Equals button is clicked:

$("#equals").click(function(){
appendToTape(expr);
buffer = eval(expr);
expr = buffer;
showBuffer();
});

This says, “When I am clicked, use
the appendToTape() function to show the expression, then set the
buffer to the solution of the expression using the eval() function.
Replace the expression with the solution (buffer), and use the
showBuffer() function to display the buffer.”


That's all for the basic operation of
the calculator. But there are a few functions remaining. These have
to do with the operation of the calculator's memory feature.


First up is the M+ key:
$("#memPlus").click(function(){
mem += buffer * 1;

$(".btnMem").addClass("btnMemFull");
});

This says, “When I am clicked, add
the buffer to the memory, then change the appearance of all the
memory feature buttons by adding the btnMemFull class to
them.”

Then we need to be able to recall the
stored value, so we add a handler to the click event of the MR key:
$("#memRecall").click(function(){
buffer = mem;

appendExpression(mem);
showBuffer();
});

This says, “When I am clicked, replace the buffer with the value in memory, use the appendExpression() function to append the value in memory to the expression, and use the showBuffer() function to display the buffer.”

Finally, we need to be able to clear the memory:
$("#memClear").click(function(){
mem = 0;

$(".btnMem").removeClass("btnMemFull");
});

This says, “When I am clicked, replace the memory value with zero, then change the appearance of all the memory feature buttons back to normal by removing the btnMemFull class from them.”

And there you have it. As always, feel free to play around with the example and make it your own.

Thursday, February 19, 2009

Simple Calculator

I am, as the saying goes, back. Life happens, and it's been happening all over the place, thereby keeping me away from jNaB. However, the results are quite nice—I'm now in a new home, and the less -than-pleasant life occurrences in the last few months are settling down and becoming a bit more manageable. So let's get back to fun stuff.

The project this time is a simple jQuery-based calculator. It's not a big deal—just 4 functions and a memory feature, along with the ability to journal all the entries. This is what is looks like:







As usual, it's organized by HTML, CSS, and JavaScript. Let's start by looking at the HTML:


<html> <head> <title>jQuery Calculator</title> <link type="text/css" rel="stylesheet" href="calc.css" /> <script type="text/javascript" src="/jquery/jquery.js"></script> <script type="text/javascript" src="calc.js"></script> </head> <body> <h1>jQuery Calculator</h1> <table id="calculator"> <tr> <td colspan="4" id="display"> </td> </tr> <tr> <td class="btnOp">+</td> <td class="btnOp">-</td> <td class="btnOp">*</td> <td class="btnOp">/</td> </tr> <tr> <td class="btnNum">7</td> <td class="btnNum">8</td> <td class="btnNum">9</td> <td class="btnMem" id="memClear">MC</td> </tr> <tr> <td class="btnNum">4</td> <td class="btnNum">5</td> <td class="btnNum">6</td> <td class="btnMem" id="memPlus">M+</td> </tr> <tr> <td class="btnNum">1</td> <td class="btnNum">2</td> <td class="btnNum">3</td> <td class="btnMem" id="memRecall">MR</td> </tr> <tr> <td class="btnNum">0</td> <td class="btnNum">.</td> <td class="btnFunc" id="clear">C</td> <td class="btnEq" id="equals">=</td> </tr> <tr><td colspan="4"><div id="tape"></div></td></tr> </table> </body> </html>

Here's the CSS:

body {
text-align: center;
font-family: Verdana, Helvetica, sans-serif;
font-size: 1em;
}
h1 {
font-size: 100%;
}
table {
border: 1px solid black;
}
#display {
border: 1px solid black;
height: 30px;
color: blue;
font: Courier New, Courier, fixed;
text-align: right;
}
.button {
font-weight: bold;
height: 30px;
width: 30px;
text-align: center;
vertical-align: center;
}
.btnNum {
background-color: silver;
}
.btnFunc {
background-color: blue;
color: white;
}
.btnMem {
background-color: blue;
color: white;
}
.btnMemFull {
background-color: green;
}
.btnOp {
background-color: blue;
color: white;
}
.btnEq {
background-color: maroon;
color: white;
}
#tape {
width: 200px;
height: auto;
border: 1px solid black;
color: black;
font: Courier New, Courier, fixed;
text-align: right;
}

And here's the JavaScript:

var buffer = "0"; var expr = "0"; var mem = 0; function appendBuffer(s){ buffer = buffer == "0" ? "" : buffer; buffer += s; } function clearBuffer(){ buffer = "0"; } function appendExpression(s){ expr += s; } function clearExpression(){ expr = ""; } function showBuffer(){ $("#display").html(buffer); } function appendToTape(s){ $("#tape").append(s); $("#tape").append("
");
} $(document).ready(function(){ $(".btnNum,.btnFunc,.btnMem,.btnMemFull,.btnOp,.btnEq").addClass("button"); $("#calculator").attr("align","center"); showBuffer(); $(".btnNum").click(function(){ appendBuffer($(this).text()); appendExpression($(this).text()); showBuffer(); }); $("#clear").click(function(){ clearBuffer(); clearExpression(); showBuffer(); }); $(".btnOp").click(function(){ if(expr > ""){ $("#equals").click(); } appendExpression($(this).text()); clearBuffer(); }); $("#equals").click(function(){ appendToTape(expr); buffer = eval(expr); expr = buffer; showBuffer(); }); $("#memPlus").click(function(){ mem += buffer * 1; $(".btnMem").addClass("btnMemFull"); }); $("#memRecall").click(function(){ buffer = mem; appendExpression(mem); showBuffer(); }); $("#memClear").click(function(){ mem = 0; $(".btnMem").removeClass("btnMemFull"); }); });

Next time: the deconstruction.