tag:blogger.com,1999:blog-23132699218800660442024-03-13T11:03:25.505-04:00jQuery Nuts and BoltsJeffhttp://www.blogger.com/profile/00213799011122065919noreply@blogger.comBlogger15125tag:blogger.com,1999:blog-2313269921880066044.post-74917300668996760042009-08-15T20:44:00.004-04:002009-08-15T21:01:43.144-04:00Red 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:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_i4Z0R0ZArEA/SodYCLtWBkI/AAAAAAAAADo/8eIfb5O2njc/s1600-h/customAlert.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 176px;" src="http://4.bp.blogspot.com/_i4Z0R0ZArEA/SodYCLtWBkI/AAAAAAAAADo/8eIfb5O2njc/s320/customAlert.png" alt="" id="BLOGGER_PHOTO_ID_5370357875188565570" border="0" /></a><br />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.<br /><span style="color: rgb(0, 153, 0);font-family:courier new;font-size:85%;" ><br /><html><br /><head><br /> <title>Javascript Alert Test</title><br /> <script type="text/javascript" src="../jquery/jquery.js"></script><br /> <style type="text/css"><br /> #msgDiv {<br /> height: auto;<br /> width: 200px;<br /> font-family: Tahoma, Helvetica, sans-serif;<br /> font-size: 80%;<br /> text-align: center;<br /> background-color: #FFAAAA;<br /> border: 1px solid red;<br /> position: absolute;<br /> top: 60px;<br /> left: 50%;<br /> margin-left: -100px;<br /> }<br /> #msgHeader {<br /> background-color: red;<br /> color: white;<br /> font-weight: bold;<br /> }<br /> #msgText {<br /> padding: 5px;<br /> }<br /> </style><br /></head><br /><body onLoad="alert('Hah!');"><br /><h2>CFFORM with Custom Alert</h2><br /><cfform name="myForm" action="" method="post"><br /> Full Name: <cfinput type="text" name="fullName" id="fullName" required="Yes" message="Enter your full name." /><br /><br /> Email: <cfinput type="text" name="email" id="email" validate="email" required="yes" message="Enter your valid email address." /><br /><br /> <cfinput type="submit" name="btnRegister" value="register" /><br /></cfform><br /><script type="text/javascript"><br /> function alert(msg){<br /> if(title == undefined){<br /> title = 'foo';<br /> }<br /> msgText = '';<br /> if (msg.typeOf = "Array"){<br /> for (i=0; i<msg.length;i++){<br /> if (msg[i] == String.fromCharCode(10)){<br /> msgText += '<br />';<br /> } else {<br /> msgText += msg[i];<br /> }<br /> }<br /> } else {<br /> msgText = msg;<br /> }<br /> alertHTML = '<div id="msgDiv"><div id="msgHeader">Error:</div><div id="msgText"</div></div>';<br /> $("body").append(alertHTML);<br /> $("#msgDiv").hide().fadeIn();<br /> $('#msgText').html(msgText + '<br /><input type="button" value="OK">')<br /> $('#msgDiv').click(function(){<br /> $(this).remove();<br /> });<br /> }<br /></script><br /></body><br /></html></span>Jeffhttp://www.blogger.com/profile/00213799011122065919noreply@blogger.com0tag:blogger.com,1999:blog-2313269921880066044.post-18696719456808599982009-08-11T20:55:00.005-04:002009-08-11T21:04:21.269-04:00A 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.<br /><br />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.<br /><br /><ul><li><a href="http://www.templatelite.com/100-popular-jquery-plugins/">http://www.templatelite.com/100-popular-jquery-plugins/</a> - 100 popular jQuery plugins</li><li><a href="http://jquery.com/">http://jquery.com/</a> - The jQuery home site</li><li><a href="http://docs.jquery.com/Utilities">http://docs.jquery.com/Utilities</a> - The jQuery documentation for jQuery utilities. You MUST visit this site.</li><li><a href="http://www.visualjquery.com/">http://www.visualjquery.com/</a> - A site that uses a jQuery-based interface to browse jQuery documentation.</li><li><a href="http://layout.jquery-dev.net/">http://layout.jquery-dev.net/</a> - The jQuery UI Layout plugin. Very flexible advanced layouts.</li></ul>Have fun!Jeffhttp://www.blogger.com/profile/00213799011122065919noreply@blogger.com0tag:blogger.com,1999:blog-2313269921880066044.post-76923505844947904002009-08-07T16:34:00.004-04:002009-08-07T16:36:39.598-04:00Class Prep WeekendNot 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.<br /><br />Have fun!Jeffhttp://www.blogger.com/profile/00213799011122065919noreply@blogger.com0tag:blogger.com,1999:blog-2313269921880066044.post-6355907758655166602009-08-06T12:08:00.003-04:002009-08-06T13:30:06.080-04:00Tooltips for Links DeconstructedYesterday'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.<br /><br />First off, the usual HTML and HEAD elements:<br /><br /><span style="color: rgb(0, 153, 0);font-family:courier new;font-size:85%;" ><html><br /><head><br /></span><span style="color: rgb(0, 153, 0);font-family:courier new;font-size:85%;" ></span><br /><br />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:<br /><br /><span style="color: rgb(0, 153, 0);font-family:courier new;" ><span style="font-size:85%;"> <script type="text/javascript" src="/jquery/jquery.js"></script><br /> <script type="text/javascript" src="/jquery/jquery.dropshadow.js"></script><br /> <script type="text/javascript" src="jqTooltips.js"></script><br /> <link type="text/css" rel="stylesheet" href="jqTooltips.css" /><br /></span><br /></span><br />And we close the head and the body:<br /><br /><span style="color: rgb(0, 153, 0);font-family:courier new;" ><span style="font-size:85%;"></head><br /><body><br /></span><br /></span><br />Now an H1 element with the page's title:<br /><br /><span style="color: rgb(0, 153, 0);font-family:courier new;" ><span style="font-size:85%;"><h1>jQuery Tooltips for Links</h1><br /></span><br /></span><br />And a paragraph to describe what we're doing:<br /><br /><span style="color: rgb(0, 153, 0);font-family:courier new;" ><span style="font-size:85%;"><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><br /></span><br /></span><br />Now we set up an unordered list that has a link in each list item:<br /><br /><span style="color: rgb(0, 153, 0);font-family:courier new;" ><span style="font-size:85%;"><ul><br /> <li><a id="lnkProtonArts" href="http://www.protonarts.com">Proton Arts</a></li><br /> <li><a id="lnkThejQueryWebsite" href="http://www.jquery.com">The jQuery Website</a></li><br /></ul><br /></span><br /></span><br />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.<br /><br />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:<br /><br /><span style="color: rgb(0, 153, 0);font-family:courier new;" ><span style="font-size:85%;"><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><br /></span><br /></span><br />And finally, the closing tags for the BODY and HTML:<br /><br /><span style="color: rgb(0, 153, 0);font-family:courier new;" ><span style="font-size:85%;"></body><br /></html><br /></span><br /></span><br />Now let's get to the CSS, since it's not very inspiring... It's in the jqTooltips.css file.<br /><br />We use the BODY element to set up the font family for the entire page.<br /><span style="color: rgb(0, 153, 0);font-family:courier new;" ><span style="font-size:85%;">body{<br /> font-family: Verdana, Helvetica, sans-serif;<br />}<br /></span><br /></span><br />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.<br /><br /><span style="color: rgb(0, 153, 0);font-family:courier new;" ><span style="font-size:85%;">.tooltip{<br /> padding: 5px 0px 0px 5px;<br /> background-color: yellow;<br /> height: 25px;<br /> font-size: 75%;<br /> font-weight: bold;<br /> text-align: center;<br /> border: 1px solid black;<br />}</span><br /></span><br />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:<br /><br /><span style="color: rgb(0, 153, 0);font-family:courier new;font-size:85%;" >function makeATooltip(atag){ //The function call includes the variable atag, which is a jQuery return set containing an A tag.<br /> tipTop = atag.offset().top - 20; //We calculate the top position of the tool tip by adding 20 to the top of the A tag.<br /> tipTop += "px"; //Now we append "px;" to the end of the tipTop variable.<br /> tipLeft = atag.offset().left + 30; //We use the same technique to calculate the left position for the tooltip.<br /> tipLeft += "px";<br />tipText = "Click on this link to visit ";<br /> tipText += atag.text(); //The text that appears in the tooltip includes the text from inside the A tag.<br /> tipText += "."; <br /> tipWidth = tipText.length * 7 + "px"; //We use the length of the tip's text to calculate the width of the tooltip.<br /> tipHTML = "<div class='tooltip' id='"; //And now we can build the HTML that describes the tooltip.<br /> tipHTML += atag.attr("id"); //We use the A tag's id attribute to assign an ID to its tooltip.<br /> tipHTML += "Tip' ";<br /> tipHTML += "style='{position: absolute;; "; //The tooltip's position is specified on the fly.<br /> tipHTML += "top: " + tipTop + ";; ";<br /> tipHTML += "left: " + tipLeft + ";; ";<br /> tipHTML += "width: " + tipWidth;<br /> tipHTML += "}'>"<br /> tipHTML += tipText<br /> tipHTML += "</div>"<br /> atag.after(tipHTML); //The HTML is injected as a new element after the A tag.<br /> $("#" + atag.attr("id") + "Tip").dropShadow(); //And we use jQuery to add a pretty drop shadow.<br />}<br /><br />function destroyTooltip(linkID){ //The function call includes the variable linkID, which is a string.<br /> $("#" + linkID + "Tip").removeShadow().remove(); //We use jQuery to remove the shadow first, then remove the tooltip.<br />}<br /><br />$(document).ready(function(){ //The ready method of the document element specifies a function to run after page load.<br /> $("a").hover(function(){ //The hover method is assigned to all A elements. It has two arguments:<br /> makeATooltip($(this)); // the first is called on mouseover<br /> }, function(){<br /> destroyTooltip($(this).attr("id")); // the second is called on mouseout<br /> });<br />})<br /></span><br />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.<br /><br />Have fun!Jeffhttp://www.blogger.com/profile/00213799011122065919noreply@blogger.com0tag:blogger.com,1999:blog-2313269921880066044.post-8951255520365949242009-08-05T08:46:00.001-04:002009-08-05T08:46:33.875-04:00Tooltips for LinksToday'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.<br />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.<br />That said, here's a screen shot of today's experiment in action:<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_i4Z0R0ZArEA/Snl5bSmTi0I/AAAAAAAAADA/YKQ5rmdAPbE/s1600-h/jQuery+Tooltips+for+Links.jpg"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 497px; height: 298px;" src="http://4.bp.blogspot.com/_i4Z0R0ZArEA/Snl5bSmTi0I/AAAAAAAAADA/YKQ5rmdAPbE/s320/jQuery+Tooltips+for+Links.jpg" alt="" id="BLOGGER_PHOTO_ID_5366453940744588098" border="0" /></a><br /><br />Here's the code, as HTML, JavaScript, and CSS. Tomorrow we'll step through it.<br /><span style="color: rgb(0, 153, 0);font-size:85%;font-family: courier new;" ><br /><html><br /><head><br /> <script type="text/javascript" src="/jquery/jquery.js"></script><br /> <script type="text/javascript" src="/jquery/jquery.dropshadow.js"></script><br /> <script type="text/javascript" src="jqTooltips.js"></script><br /> <link type="text/css" rel="stylesheet" href="jqTooltips.css"><br /></head><br /><body><br /><h1>jQuery Tooltips for Links</h1><br /><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:<br /><br /><ul><br /> <li><a id="lnkProtonArts" href="http://www.protonarts.com">Proton Arts</a></li><br /> <li><a id="lnkThejQueryWebsite" href="http://www.jquery.com">The jQuery Website</a></li><br /></ul><br /><br /><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><br /></body><br /></html><br /></span><br />JavaScript:<br /><br /><span style="color: rgb(0, 153, 0);font-size:85%;font-family: courier new;"><br />function makeATooltip(atag){<br /> tipTop = atag.offset().top - 20;<br /> tipTop += "px";<br /> tipLeft = atag.offset().left + 30;<br /> tipLeft += "px";<br /> tipText = "Click on this link to visit " + atag.text() + ".";<br /> tipWidth = tipText.length * 7 + "px";<br /> tipHTML = "<div class='tooltip' id='"; <br /> tipHTML += atag.attr("id"); <br /> tipHTML += "Tip' ";<br /> tipHTML += "style='{position: absolute;; ";<br /> tipHTML += "top: " + tipTop + ";; ";<br /> tipHTML += "left: " + tipLeft + ";; ";<br /> tipHTML += "width: " + tipWidth;<br /> tipHTML += "}'>"<br /> tipHTML += tipText <br /> tipHTML += "</div>"<br /> atag.after(tipHTML);<br /> $("#" + atag.attr("id") + "Tip").dropShadow();<br />}<br /><br />function destroyTooltip(linkID){<br /> $("#" + linkID + "Tip").removeShadow().remove();<br />}<br /><br />$(document).ready(function(){<br /> $("a").hover(function(){<br /> makeATooltip($(this));<br /> }, function(){<br /> destroyTooltip($(this).attr("id"));<br /> });<br />})<br /></span><br /><br /><span style="color: rgb(0, 0, 0);">CSS:</span><br /><span style="font-size:85%;"><br /><span style="color: rgb(0, 153, 0);"><span style="font-family: courier new;">body{<br /> font-family: Verdana, Helvetica, sans-serif;<br />}<br /><br />.tooltip{<br /> padding: 5px 0px 0px 5px;<br /> background-color: yellow;<br /> height: 25px;<br /> font-family: Verdana, Helvetica, sans-serif;<br /> font-size: 75%;<br /> font-weight: bold;<br /> text-align: center;<br /> border: 1px solid black;<br />}<br /></span></span></span><br />See you tomorrow!Jeffhttp://www.blogger.com/profile/00213799011122065919noreply@blogger.com0tag:blogger.com,1999:blog-2313269921880066044.post-71461865340885808402009-08-04T14:58:00.002-04:002009-08-04T15:08:44.311-04:00Back (I Hope) on a More Regular BasisTo 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.<br /><br />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.<br /><br />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.<br /><br />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 <a href="http://www.CFUnited.com">www.CFUnited.com</a> and look under "Classes".<br /><br />And for tomorrow: a little piece of jQuery to make instant tool tips out of links. That should be fun and not too complex.Jeffhttp://www.blogger.com/profile/00213799011122065919noreply@blogger.com0tag:blogger.com,1999:blog-2313269921880066044.post-62189034194607058082009-07-07T22:26:00.003-04:002009-07-07T22:42:15.853-04:00Live and In PersonAh, 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.<br /><br />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 <a href="http://www.cfunited.com/">http://www.cfunited.com</a>.<br /><br />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.<br /><br />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 <a href="http://www.protonarts.com/index.cfm?fuseaction=Books.showBookDept">ProtonArts.com</a> or <a href="http://www.amazon.com/Fusebox-Developing-ColdFusion-Applications-Voices/dp/0735712697/ref=sr_1_1?ie=UTF8&s=books&qid=1247020777&sr=1-1">Amazon.com</a>.<br /><br />If you do decide to go, let me know. I'll look forward to seeing you there!Jeffhttp://www.blogger.com/profile/00213799011122065919noreply@blogger.com0tag:blogger.com,1999:blog-2313269921880066044.post-88354782427914555872009-02-23T14:45:00.003-05:002009-02-23T15:43:24.214-05:00Simple Calculator Deconstructed<p style="margin-bottom: 0in;">Here's the deconstruction of the<br />calculator project, starting with the HTML:</p><br /><p style="margin-bottom: 0in;"><span style="color:#008000;"><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" ><html><br /><head><br /><title>jQuery Calculator</title><br /><link type="text/css" rel="stylesheet" href="calc.css"/> </span></span></span><span style="color:#008000;"><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" ><br /><scripttype="text/javascript" src="/jquery/jquery.js"></script><br /><script type="text/javascript" src="calc.js"></script><br /></head><br /><body><br /><h1>jQuery Calculator</h1><br /><tableid="calculator"><br /><tr><br /><td colspan="4" id="display">&nbsp;</td><br /></tr><br /><tr><br /><td class="btnOp">+</td> </span></span></span><span style="color:#008000;"><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" ><br /><td class="btnOp">-</td><br /><td class="btnOp">*</td><br /><td class="btnOp">/</td><br /></tr><br /><tr><br /><td class="btnNum">7</td><br /><td class="btnNum">8</td><br /><td class="btnNum">9</td><br /><td class="btnMem" id="memClear">MC</td><br /></tr><br /><tr><br /><td class="btnNum">4</td><br /><td class="btnNum">5</td><br /><td class="btnNum">6</td><br /><td class="btnMem" id="memPlus">M+</td><br /></tr><br /><tr><br /><td class="btnNum">1</td><br /><td class="btnNum">2</td><br /><td class="btnNum">3</td><br /><td class="btnMem" id="memRecall">MR</td><br /></tr><br /><tr><br /><td class="btnNum">0</td><br /><td class="btnNum">.</td><br /><td class="btnFunc" id="clear">C</td><br /><td class="btnEq" id="equals">=</td><br /></tr><br /><tr><td colspan="4"><div id="tape"></div></td></tr><br /></table><br /></body><br /></html></span></span></span></p><br /><p style="margin-bottom: 0in;">This is very straightforward stuff.<br />Notice the lack of anything beyond basic HTML here—the idea is to<br />keep it simple and clean. Our rule is HTML = content (nouns), CSS =<br />appearance (adjectives), and JavaScript = behavior (verbs). So the<br />HTML sets up the nouns—a calculator table with number buttons,<br />operator buttons, function buttons, memory buttons, and an equals<br />button; and a “tape” div to display the journal.</p><br /><p style="margin-bottom: 0in;">This HTML, if rendered without CSS,<br />isn't very pretty. It looks like this:</p><br /><p style="margin-bottom: 0in;"><br /><br /></p><br /><p style="margin-bottom: 0in;"><img src="http://i353.photobucket.com/albums/r370/cortplayer/jquery%20calculator/Screenshot-jQueryCalculator-Mozilla.png" name="graphics1" align="bottom" border="0" height="26%" /></p><br /><p style="margin-bottom: 0in;">So, we need to dress it up a bit—time<br />for the CSS. The CSS code contained in the project's stylesheet<br />looks like this:</p><br /><p style="margin-bottom: 0in;"><span style="color:#008000;"><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >body{<br />text-align: center;<br />font-family: Verdana, Helvetica, sans-serif;<br />font-size: 1em;<br />}<br />h1{<br />font-size: 100%;<br />}<br />table{<br />border: 1px solid black;<br />}<br />#display {<br />border: 1px solid black;<br />height: 30px;<br />color: blue;<br />font: Courier New, Courier, fixed;<br />text-align: right;<br />}<br />.button{<br />font-weight: bold;<br />height: 30px;<br />width: 30px;<br />text-align: center;<br />vertical-align: center;<br />}<br />.btnNum{</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >background-color: silver;<br />}<br />.btnFunc {</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >background-color: blue;<br />color: white;<br />}<br />.btnMem<br />{</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >background-color: blue;<br />color: white;<br />}<br />.btnMemFull{</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >background-color: green;<br />}<br />.btnOp{</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >background-color: blue;<br />color: white;<br />}<br />.btnEq{</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >background-color: maroon;<br />color: white;<br />}<br />#tape{<br />width: 200px;<br />height:auto;<br />border: 1px solid black;<br />color: black;<br />font: Courier New, Courier, fixed;<br />text-align: right;<br />}</span></span></span><br /></p><br /><p style="margin-bottom: 0in;">All we're doing here is setting up<br />borders, fonts and colors for the various parts of the calculator. A<br />couple of classes to note in particular are the <b>btnMemFull</b><br />class and the <b>button</b> class. They aren't referenced anywhere<br />in the HTML. These are classes that will be used by the JavaScript<br />via jQuery.</p><br /><p style="margin-bottom: 0in;">If we render the HTML with just the CSS<br />activated, it looks better than before, but not quite complete.<br />Notice the text on the buttons isn't centered, the buttons aren't<br />uniform, and the calculator isn't centered on the page. <br /></p><br /><p style="margin-bottom: 0in;"><img src="http://i353.photobucket.com/albums/r370/cortplayer/jquery%20calculator/Screenshot-jQueryCalculator-Mozi-2.png" name="graphics2" align="bottom" border="0" height="26%" /></p><br /><p style="margin-bottom: 0in;">These details will be picked up by the<br />JavaScript, by applying an attribute to the table and the button<br />class to all the buttons. We'll see that in a minute. First let's<br />take a look at all the JavaScript for the project:</p><br /><p style="margin-bottom: 0in;"><span style="color:#008000;"><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >var buffer = "0";<br />var expr = "0";<br />varmem = 0;<br />function appendBuffer(s){<br />buffer = buffer == "0" ? "" : buffer;<br />buffer += s;<br />}<br />function clearBuffer(){ buffer = "0"; }<br />function appendExpression(s){ expr += s; sd}<br />function clearExpression(){ expr = ""; }<br />function showBuffer(){ $("#display").html(buffer); }<br />function appendToTape(s){</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$("#tape").append(s)</span></span><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >.append("<br />");</span></span></span><br /></p><p style="margin-bottom: 0in;"><span style="color:#008000;"><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$(document).ready(function(){</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$(".btnNum,.btnFunc,.btnMem,.btnMemFull,.btnOp,.btnEq").addClass("button");</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$("#calculator").attr("align","center");<br />showBuffer();</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$(".btnNum").click(function(){</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >appendBuffer($(this).text());</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >appendExpression($(this).text());<br />showBuffer();<br />});</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$("#clear").click(function(){</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >clearBuffer();</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >clearExpression();<br />showBuffer();<br />});</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$(".btnOp").click(function(){<br />if(expr > ""){</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$("#equals").click();<br />}</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >appendExpression($(this).text());</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >clearBuffer();<br />});</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$("#equals").click(function(){</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >appendToTape(expr);<br />buffer = eval(expr);<br />expr = buffer;<br />showBuffer();<br />});</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$("#memPlus").click(function(){<br />mem += buffer * 1;</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$(".btnMem").addClass("btnMemFull");<br />});</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$("#memRecall").click(function(){<br />buffer = mem;</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >appendExpression(mem);<br />showBuffer();<br />});</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$("#memClear").click(function(){<br />mem = 0;</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$(".btnMem").removeClass("btnMemFull");<br />});<br />});</span></span></span><br /></p><p style="margin-bottom: 0in;">That's all there is to it—a<br />completely functional calculator. So let's step through the<br />JavaScript and see what's going on in there. First, we set up three<br />variables to store global values for the buffer (to be displayed),<br />the expression (to be calculated), and the memory value (used when<br />any of the M buttons is clicked):</p><br /><p style="margin-bottom: 0in;"><span style="color:#008000;"><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >var buffer = "0";<br />var expr = "0";<br />var mem = 0; </span></span></span><br /></p><br /><p style="margin-bottom: 0in;">Next we set up six functions that will<br />be used later in the processing. They allow us to manipulate the<br />buffer, the expression, and the value in the <b>tape</b> div. These<br />are placed in separate functions instead of button-bound functions<br />because we want to be able to use these functions from several<br />different places in the application, as we'll see when we start<br />looking at the button-bound code.</p><br /><p style="margin-bottom: 0in;">Now we get into the code that is run<br />when the document loads, as indicated by the <b>$(document).ready()</b><br />construct. Just as a reminder, this is the way jQuery allows us to<br />specify code that will be fun after the document has successfully<br />loaded into the browser. The first three lines define actions that<br />will take place right away. The button class is applied to every<br />member of the classes that define various types of buttons, then the<br />calculator table is aligned in the window, and the value of the<br />buffer variable is displayed in the calculator's display window:</p><br /><p style="margin-bottom: 0in;"><span style="color:#008000;"><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$(".btnNum,.btnFunc,.btnMem,.btnMemFull,.btnOp,.btnEq").addClass("button");<br />$("#calculator").attr("align","center");<br />showBuffer();</span></span></span><br /></p><p style="margin-bottom: 0in;">Rendering with the JavaScript activated<br />shows that the calculator has taken on its final appearance as a<br />result of those three lines:</p><br /><p style="margin-bottom: 0in;"><img src="http://i353.photobucket.com/albums/r370/cortplayer/jquery%20calculator/Screenshot-jQueryCalculator-Mozi-1.png" name="graphics3" align="bottom" border="0" height="26%" /></p><br /><p style="margin-bottom: 0in;">So that's much better. Everything is<br />aligned where we want it, and the buttons are all nice and uniform,<br />with their appropriate sizes and fonts.</p><br /><p style="margin-bottom: 0in;">Now we need a few functions to handle<br />the non-button-specific work of the calculator. We need a way to add<br />values to the buffer (for display):</p><br /><p style="margin-bottom: 0in;"><span style="color:#008000;"><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >function appendBuffer(s){<br />buffer = buffer == "0" ? "" : buffer;<br />buffer += s;<br />}</span></span></span><br /></p><p style="margin-bottom: 0in;">This function says, “if the value of<br />buffer equals zero, set the buffer to an empty string; otherwise<br />leave its value as it was. Then append the string passed into the<br />function to the buffer.” The ternary operation in the first line<br />gets rid of the zero when a number is appended at the beginning of a<br />calcuation.<br /></p><p style="margin-bottom: 0in;">We also need a way to clear the buffer.<br />We want the calculator to display zero when it's not busy, so the<br />function just replaces the buffer value with zero:<br /></p><br /><p style="margin-bottom: 0in;"><span style="color:#008000;"><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >function clearBuffer(){ buffer = "0"; }<br /></span></span></span></p><br /><p style="margin-bottom: 0in;">Similarly, we need functions to handle<br />appending to and clearing the expression. The expression is similar<br />to the buffer, except that it also handles the operators that are<br />clicked. Operators do not get displayed in the calculator's window.<br /></p><br /><p style="margin-bottom: 0in;"><span style="color:#008000;"><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >function appendExpression(s){ expr += s; }<br />function clearExpression(){ expr = ""; }<br /></span></span></span></p><br /><p style="margin-bottom: 0in;">Speaking of the calculator's window,<br />here's the function that displays the contents of the buffer in that<br />window:<br /></p><br /><p style="margin-bottom: 0in;"><span style="color:#008000;"><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >function showBuffer(){ $("#display").html(buffer); }<br /></span></span></span></p><br /><p style="margin-bottom: 0in;">This says, “Use the jQuery html()<br />method to replace the HTML inside the element whose id is 'display'<br />with the contents of the buffer.”</p><br /><p style="margin-bottom: 0in;">And we need a way to print out lines in the journal (or “tape”) as well:</p><p style="margin-bottom: 0in;"><span style="color:#008000;"><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >function appendToTape(s){</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$("#tape").append(s).append("<br/>");<br />}</span></span></span></p><br /><p style="margin-bottom: 0in;">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.”</p><br /><p style="margin-bottom: 0in;">The rest of the JavaScript assigns<br />various functions to the click event of the buttons on the<br />calculator. Let's take a look a them in sections and see what's<br />going on.</p><br /><p style="margin-bottom: 0in;">The first section is composed of four<br />functions which establish the basic functioning of the calculator.<br />First, we have a function that controls the behavior of each of the<br />number buttons:</p><br /><p style="margin-bottom: 0in;"><span style="color:#008000;"><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$(".btnNum").click(function(){<br /></span></span></span></p><br /><p style="margin-bottom: 0in;"><span style="color:#008000;"> <br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >appendBuffer($(this).text());<br /></span></span></span></p><br /><p style="margin-bottom: 0in;"><span style="color:#008000;"> <br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >appendExpression($(this).text());<br /></span></span></span></p><br /><p style="margin-bottom: 0in;"><span style="color:#008000;"> <br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >showBuffer();<br /></span></span></span></p><br /><p style="margin-bottom: 0in;"><span style="color:#008000;"> <span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >});<br /></span></span></span></p><br /><p style="margin-bottom: 0in;">This just says, “When I am clicked,<br />my text (number) is appended to the buffer and the expression using<br />the appendBuffer() and appendExpression() functions, and the buffer<br />is shown in the display using the showBuffer() function.” <br /></p><br /><p style="margin-bottom: 0in;">We then have a function that controls<br />what happens when the “C” button is clicked:</p><br /><p style="margin-bottom: 0in;"><span style="color:#008000;"><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$("#clear").click(function(){</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >clearBuffer();</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >clearExpression();</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >showBuffer();<br />});</span></span></span><br /></p><p style="margin-bottom: 0in;">This says, “When I am clicked, run<br />the clearBuffer() and clearExpression() functions to empty the buffer<br />and expression, and show the buffer in the display using the<br />showBuffer() function.”</p><br /><p style="margin-bottom: 0in;">Then we have a function that controls<br />the behavior of each of the operator buttons:<br /></p><p style="margin-bottom: 0in;"><span style="color:#008000;"><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$(".btnOp").click(function(){<br />if(expr > ""){</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$("#equals").click();<br />}</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >appendExpression($(this).text());</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >clearBuffer();<br />});</span></span></span><br /></p><p style="margin-bottom: 0in;">This says, “When I am clicked, if<br />there is something in the expression then click the Equals button.<br />Then use the appendExpression() function to add my text (operator) to<br />the expression, and use the clearBuffer() function to empty the<br />buffer.” Using this approach allows us to add operators to the<br />expression without showing them in the display (buffer).</p><br /><p style="margin-bottom: 0in;">Finally, we have a function that<br />controls what happens when the Equals button is clicked:<br /><br /></p><span style="color:#008000;"><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$("#equals").click(function(){<br /></span></span></span><span style="color:#008000;"><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >appendToTape(expr);<br /></span></span></span><span style="color:#008000;"><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >buffer = eval(expr);<br /></span></span></span><span style="color:#008000;"><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >expr = buffer;<br /></span></span></span><span style="color:#008000;"><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >showBuffer();<br /></span></span></span><span style="color:#008000;"><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >});<br /></span></span></span><br /><p style="margin-bottom: 0in;">This says, “When I am clicked, use<br />the appendToTape() function to show the expression, then set the<br />buffer to the solution of the expression using the eval() function.<br />Replace the expression with the solution (buffer), and use the<br />showBuffer() function to display the buffer.” <br /></p><br /><p style="margin-bottom: 0in;">That's all for the basic operation of<br />the calculator. But there are a few functions remaining. These have<br />to do with the operation of the calculator's memory feature.</p><br /><p style="margin-bottom: 0in;">First up is the M+ key:<span style="color:#008000;"><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$("#memPlus").click(function(){<br />mem += buffer * 1;</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$(".btnMem").addClass("btnMemFull");<br />});</span></span></span><br /></p><p style="margin-bottom: 0in;">This says, “When I am clicked, add<br />the buffer to the memory, then change the appearance of all the<br />memory feature buttons by adding the <b>btnMemFull</b> class to<br />them.”<br /></p><p style="margin-bottom: 0in;">Then we need to be able to recall the<br />stored value, so we add a handler to the click event of the MR key:<span style="color:#008000;"><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$("#memRecall").click(function(){<br />buffer = mem;</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >appendExpression(mem);</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >showBuffer();<br />});</span></span></span><br /></p><p style="margin-bottom: 0in;">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.”<br /></p><p style="margin-bottom: 0in;">Finally, we need to be able to clear the memory:<span style="color:#008000;"><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$("#memClear").click(function(){<br />mem = 0;</span></span><br /><span style="font-family:Courier 10 Pitch;"><span style="font-size: 8pt;font-size:78%;" >$(".btnMem").removeClass("btnMemFull");<br />});</span></span></span><br /></p><p style="margin-bottom: 0in;">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 <b>btnMemFull </b>class from them.”</p><p style="margin-bottom: 0in;">And there you have it. As always, feel free to play around with the example and make it your own.<br /></p>Jeffhttp://www.blogger.com/profile/00213799011122065919noreply@blogger.com1tag:blogger.com,1999:blog-2313269921880066044.post-32177653333592836372009-02-19T10:54:00.003-05:002009-02-19T13:44:09.865-05:00Simple CalculatorI 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.</p> <p style="margin-bottom: 0in;">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:</p><p style="margin-bottom: 0in;"><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_i4Z0R0ZArEA/SZ2n80YbEfI/AAAAAAAAAC4/pYUSQMcVbkY/s1600-h/Screenshot-jQuery+Calculator+-+Mozilla+Firefox-2.png"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 320px; height: 199px;" src="http://2.bp.blogspot.com/_i4Z0R0ZArEA/SZ2n80YbEfI/AAAAAAAAAC4/pYUSQMcVbkY/s320/Screenshot-jQuery+Calculator+-+Mozilla+Firefox-2.png" alt="" id="BLOGGER_PHOTO_ID_5304580599407383026" border="0" /></a></p><p style="margin-bottom: 0in;"><img src="file:///home/jeff/Desktop/Screenshot-jQuery%2520Calculator%2520-%2520Mozilla%2520Firefox-2.png" alt="" /></p><p style="margin-bottom: 0in;"><br /> </p><p style="margin-bottom: 0in;"><br /></p><p style="margin-bottom: 0in;"><br /></p><p style="margin-bottom: 0in;"><br /></p><p style="margin-bottom: 0in;"><br /></p><p style="margin-bottom: 0in;"><br /></p><p style="margin-bottom: 0in;">As usual, it's organized by HTML, CSS, and JavaScript. Let's start by looking at the HTML:</p><br /><span style="font-family:trebuchet ms;font-size:85%;"><span style="color: rgb(0, 153, 0);"><html></span> <span style="color: rgb(0, 153, 0);"><head></span> <span style="color: rgb(0, 153, 0);"> <title>jQuery Calculator</title></span> <span style="color: rgb(0, 153, 0);"> <link type="text/css" rel="stylesheet" href="calc.css" /></span> <span style="color: rgb(0, 153, 0);"> <script type="text/javascript" src="/jquery/jquery.js"></script></span> <span style="color: rgb(0, 153, 0);"> <script type="text/javascript" src="calc.js"></script></span> <span style="color: rgb(0, 153, 0);"></head></span> <span style="color: rgb(0, 153, 0);"><body></span> <span style="color: rgb(0, 153, 0);"><h1>jQuery Calculator</h1></span> <span style="color: rgb(0, 153, 0);"><table id="calculator"></span> <span style="color: rgb(0, 153, 0);"> <tr></span> <span style="color: rgb(0, 153, 0);"> <td colspan="4" id="display"> </td></span> <span style="color: rgb(0, 153, 0);"> </tr></span> <span style="color: rgb(0, 153, 0);"> <tr></span> <span style="color: rgb(0, 153, 0);"> <td class="btnOp">+</td></span> <span style="color: rgb(0, 153, 0);"> <td class="btnOp">-</td></span> <span style="color: rgb(0, 153, 0);"> <td class="btnOp">*</td></span> <span style="color: rgb(0, 153, 0);"> <td class="btnOp">/</td></span> <span style="color: rgb(0, 153, 0);"> </tr></span> <span style="color: rgb(0, 153, 0);"> <tr></span> <span style="color: rgb(0, 153, 0);"> <td class="btnNum">7</td></span> <span style="color: rgb(0, 153, 0);"> <td class="btnNum">8</td></span> <span style="color: rgb(0, 153, 0);"> <td class="btnNum">9</td></span> <span style="color: rgb(0, 153, 0);"> <td class="btnMem" id="memClear">MC</td></span> <span style="color: rgb(0, 153, 0);"> </tr></span> <span style="color: rgb(0, 153, 0);"> <tr></span> <span style="color: rgb(0, 153, 0);"> <td class="btnNum">4</td></span> <span style="color: rgb(0, 153, 0);"> <td class="btnNum">5</td></span> <span style="color: rgb(0, 153, 0);"> <td class="btnNum">6</td></span> <span style="color: rgb(0, 153, 0);"> <td class="btnMem" id="memPlus">M+</td></span> <span style="color: rgb(0, 153, 0);"> </tr></span> <span style="color: rgb(0, 153, 0);"> <tr></span> <span style="color: rgb(0, 153, 0);"> <td class="btnNum">1</td></span> <span style="color: rgb(0, 153, 0);"> <td class="btnNum">2</td></span> <span style="color: rgb(0, 153, 0);"> <td class="btnNum">3</td></span> <span style="color: rgb(0, 153, 0);"> <td class="btnMem" id="memRecall">MR</td></span> <span style="color: rgb(0, 153, 0);"> </tr></span> <span style="color: rgb(0, 153, 0);"> <tr></span> <span style="color: rgb(0, 153, 0);"> <td class="btnNum">0</td></span> <span style="color: rgb(0, 153, 0);"> <td class="btnNum">.</td></span> <span style="color: rgb(0, 153, 0);"> <td class="btnFunc" id="clear">C</td></span> <span style="color: rgb(0, 153, 0);"> <td class="btnEq" id="equals">=</td></span> <span style="color: rgb(0, 153, 0);"> </tr></span> <span style="color: rgb(0, 153, 0);"> <tr><td colspan="4"><div id="tape"></div></td></tr></span> <span style="color: rgb(0, 153, 0);"></table></span> <span style="color: rgb(0, 153, 0);"></body></span> <span style="color: rgb(0, 153, 0);"></html></span></span><br /><br /><p>Here's the CSS:</p><p><span style="color: rgb(0, 153, 0); font-family: trebuchet ms;font-size:85%;" >body {<br /> text-align: center;<br /> font-family: Verdana, Helvetica, sans-serif;<br /> font-size: 1em;<br />}<br />h1 {<br /> font-size: 100%;<br />}<br />table {<br /> border: 1px solid black;<br />}<br />#display {<br /> border: 1px solid black;<br /> height: 30px;<br /> color: blue;<br /> font: Courier New, Courier, fixed;<br /> text-align: right;<br />}<br />.button {<br /> font-weight: bold;<br /> height: 30px;<br /> width: 30px;<br /> text-align: center;<br /> vertical-align: center;<br />}<br />.btnNum {<br /> background-color: silver;<br />}<br />.btnFunc {<br /> background-color: blue;<br /> color: white;<br />}<br />.btnMem {<br /> background-color: blue;<br /> color: white;<br />}<br />.btnMemFull {<br /> background-color: green;<br />}<br />.btnOp {<br /> background-color: blue;<br /> color: white;<br />}<br />.btnEq {<br /> background-color: maroon;<br /> color: white;<br />}<br />#tape {<br /> width: 200px;<br /> height: auto;<br /> border: 1px solid black;<br /> color: black;<br /> font: Courier New, Courier, fixed;<br /> text-align: right;<br />}</span><br /></p><p face="times new roman" style="margin-bottom: 0in; color: rgb(0, 0, 0);">And here's the JavaScript:</p><p style="margin-bottom: 0in; font-family: times new roman; color: rgb(0, 0, 0);"><span style="color: rgb(0, 153, 0);font-size:85%;" ><span style="font-family:courier new;">var buffer = "0";</span> <span style="font-family:courier new;">var expr = "0";</span> <span style="font-family:courier new;">var mem = 0;</span> <span style="font-family:courier new;">function appendBuffer(s){</span> <span style="font-family:courier new;"> buffer = buffer == "0" ? "" : buffer;</span> <span style="font-family:courier new;"> buffer += s; </span> <span style="font-family:courier new;">}</span> <span style="font-family:courier new;">function clearBuffer(){ buffer = "0"; }</span> <span style="font-family:courier new;">function appendExpression(s){ expr += s; }</span> <span style="font-family:courier new;">function clearExpression(){ expr = ""; }</span> <span style="font-family:courier new;">function showBuffer(){ $("#display").html(buffer); }</span> <span style="font-family:courier new;">function appendToTape(s){</span> <span style="font-family:courier new;"> $("#tape").append(s);</span> <span style="font-family:courier new;"> $("#tape").append("<br />");</span> <span style="font-family:courier new;">}</span> <span style="font-family:courier new;">$(document).ready(function(){</span> <span style="font-family:courier new;"> $(".btnNum,.btnFunc,.btnMem,.btnMemFull,.btnOp,.btnEq").addClass("button");</span> <span style="font-family:courier new;"> $("#calculator").attr("align","center");</span> <span style="font-family:courier new;"> showBuffer();</span> <span style="font-family:courier new;"> $(".btnNum").click(function(){</span> <span style="font-family:courier new;"> appendBuffer($(this).text());</span> <span style="font-family:courier new;"> appendExpression($(this).text());</span> <span style="font-family:courier new;"> showBuffer();</span> <span style="font-family:courier new;"> });</span> <span style="font-family:courier new;"> $("#clear").click(function(){</span> <span style="font-family:courier new;"> clearBuffer();</span> <span style="font-family:courier new;"> clearExpression();</span> <span style="font-family:courier new;"> showBuffer();</span> <span style="font-family:courier new;"> });</span> <span style="font-family:courier new;"> $(".btnOp").click(function(){</span> <span style="font-family:courier new;"> if(expr > ""){</span> <span style="font-family:courier new;"> $("#equals").click();</span> <span style="font-family:courier new;"> }</span> <span style="font-family:courier new;"> appendExpression($(this).text());</span> <span style="font-family:courier new;"> clearBuffer();</span> <span style="font-family:courier new;"> });</span> <span style="font-family:courier new;"> $("#equals").click(function(){</span> <span style="font-family:courier new;"> appendToTape(expr);</span> <span style="font-family:courier new;"> buffer = eval(expr);</span> <span style="font-family:courier new;"> expr = buffer;</span> <span style="font-family:courier new;"> showBuffer();</span> <span style="font-family:courier new;"> });</span> <span style="font-family:courier new;"> $("#memPlus").click(function(){</span> <span style="font-family:courier new;"> mem += buffer * 1;</span> <span style="font-family:courier new;"> $(".btnMem").addClass("btnMemFull");</span> <span style="font-family:courier new;"> });</span> <span style="font-family:courier new;"> $("#memRecall").click(function(){</span> <span style="font-family:courier new;"> buffer = mem;</span> <span style="font-family:courier new;"> appendExpression(mem);</span> <span style="font-family:courier new;"> showBuffer();</span> <span style="font-family:courier new;"> });</span> <span style="font-family:courier new;"> $("#memClear").click(function(){</span> <span style="font-family:courier new;"> mem = 0;</span> <span style="font-family:courier new;"> $(".btnMem").removeClass("btnMemFull");</span> <span style="font-family:courier new;"> });</span> <span style="font-family:courier new;">});</span><br /></span><br /></p><p style="margin-bottom: 0in; font-family: times new roman; color: rgb(0, 0, 0);">Next time: the deconstruction.</p><p style="margin-bottom: 0in; font-family: times new roman; color: rgb(0, 0, 0);"><br /></p>Jeffhttp://www.blogger.com/profile/00213799011122065919noreply@blogger.com0tag:blogger.com,1999:blog-2313269921880066044.post-68746935386035856212008-08-30T14:05:00.003-04:002008-08-30T14:18:46.259-04:00Momentary HiatusI've taken a couple of days off to see my latest book into print. If you're a ColdFusion developer, take a look at "How to Drive Fusebox 5.5", available at <a href="http://www.protonarts.com/">Proton Arts</a>.<br /><br />And, to keep things on the jQuery front alive, here's a great project from Michael Sprague: <a href="http://www.webtrenches.com/post.cfm/jquery-replacements-for-cfgride-cfwindowe-and-cftooltip">CFjqAJAX</a>, a library of jQuery tools designed to replace CFGRID, CFWINDOW and CFTOOLTIP in ColdFusion 8. (Thanks to <a href="http://www.corfield.org/">Sean Corfield</a> for the heads-up).Jeffhttp://www.blogger.com/profile/00213799011122065919noreply@blogger.com0tag:blogger.com,1999:blog-2313269921880066044.post-52303959898439965252008-08-27T12:16:00.002-04:002008-08-27T12:54:32.661-04:00A Popup Form DeconstructedLooking at the JavaScript code from "A Popup Form", there are really only two things going on in this function. The first is that we build this huge string named <span style="font-weight: bold;">s</span>. The second thing is that we inject that HTML into the document using jQuery:<br /><pre><br /><span style="color: rgb(0, 153, 0);">$("body").append(s);</span><br /></pre><br />This causes the form to pop up. But the fun stuff is really happening within that HTML string named <span style="font-weight: bold;">s</span>. So let's take a look at its parts and see what they do.<br /><br />First thing to mention is that this piece of code breaks one of my favorite best practices--keeping content (HTML), display (CSS) and behavior (JavaScript) in distinct files. It's a trade-off. The idea behind this example is that we have a very small form that we might want to use in several places in the application. By having it all included in a single JavaScript file, we can easily leverage it wherever we want. Anyway, back to the code.<br /><br />There are three sections of code inside <span style="font-weight: bold;">s</span>: the CSS, the HTML, and the JavaScript. We'll look at each individually, starting with the CSS.<br /><br /><pre><br /><span style="color: rgb(0, 153, 0);"><style></span><br /><span style="color: rgb(0, 153, 0);"> #formDiv {</span><br /><span style="color: rgb(0, 153, 0);"> position: absolute;</span><br /><span style="color: rgb(0, 153, 0);"> top: 100px;</span><br /><span style="color: rgb(0, 153, 0);"> left: 100px;</span><br /><span style="color: rgb(0, 153, 0);"> background-color: #D9E8D7;</span><br /><span style="color: rgb(0, 153, 0);"> color: #33532F;</span><br /><span style="color: rgb(0, 153, 0);"> border: 1px solid #33532F;</span><br /><span style="color: rgb(0, 153, 0);"> padding: 12px 6px 0px 6px;</span><br /><span style="color: rgb(0, 153, 0);"> font-family: Tahoma, Helvetica, sans-serif;</span><br /><span style="color: rgb(0, 153, 0);"> font-size: 9pt;</span><br /><span style="color: rgb(0, 153, 0);"> text-align: center;</span><br /><span style="color: rgb(0, 153, 0);"> }</span><br /><span style="color: rgb(0, 153, 0);"></style></span><br /></pre>This is just plain old CSS to position, size, and color the popup the way we want it. One important thing to note is the use of <span style="font-weight: bold;">position: absolute</span>. Since this div is being injected a the end of the content of the body element, it's reasonably safe to position it absolutely (i.e., from the body element's upper left corner).<br /><br />The we have the HTML section of the code:<br /><pre><br /><span style="color: rgb(0, 102, 0);"><div id="formDiv"></span><br /><span style="color: rgb(0, 102, 0);"> <strong>New Employee</strong><br /><br /></span><br /><span style="color: rgb(0, 102, 0);"> <form name="newEmployeeForm" id="newEmployeeForm" method="post"></span><br /><span style="color: rgb(0, 102, 0);"> First Name: <input id="firstName" name="firstName" type="text" /><br /></span><br /><span style="color: rgb(0, 102, 0);"> Last Name: <input id="lastName" name="lastName" type="text" /><br /></span><br /><span style="color: rgb(0, 102, 0);"> <input type="submit" name="btnSave" id="btnSave" value="Save"></span><br /><span style="color: rgb(0, 102, 0);"> <input type="button" name="btnCancel" id="btnCancel" value="Cancel"></span><br /><span style="color: rgb(0, 102, 0);"> </form></span><br /><span style="color: rgb(0, 102, 0);"></div></span><br /></pre>Again, nothing fancy here--just basic HTML to display the popup's title, text inputs for firstName and lastName, and buttons for Save and Cancel. Notice, though, the use of id attributes for all the inputs and the popup's div. These are critical for the next part--the JavaScript.<br /><pre><br /><span style="color: rgb(0, 102, 0);"><script type="text/javascript"></span><br /><span style="color: rgb(0, 102, 0);"> formInfo = "";<br /></span></pre>We start by setting the formInfo variable to an empty string. This just makes sure we're not carrying around extra information by chance.<br /><br /><pre><br /><span style="color: rgb(0, 153, 0);"> $("#btnCancel").click(function(){</span><br /><span style="color: rgb(0, 153, 0);"> returnResponse("Cancelled");</span><br /><span style="color: rgb(0, 153, 0);"> });</span><br /></pre><br />Now we set the button whose id is <span style="font-weight: bold;">btnCancel</span> to call the returnResponse() function when clicked. It includes the string "Cancelled" as an argument to the function.<br /><pre><br /><span style="color: rgb(0, 102, 0);"> $("#newEmployeeForm").submit(function(){</span><br /><span style="color: rgb(0, 102, 0);"> formInfo = new Object;</span><br /><span style="color: rgb(0, 102, 0);"> formInfo.firstName = $("#firstName").val();</span><br /><span style="color: rgb(0, 102, 0);"> formInfo.lastName = $("#lastName").val();</span><br /><span style="color: rgb(0, 102, 0);"> returnResponse(formInfo);</span><br /><span style="color: rgb(0, 102, 0);"> });</span><br /></pre><br />Now we assign some behavior to the form itself (id is <span style="font-weight: bold;">newEmployeeForm</span>). When the form is submitted, we create a new Object and save it with the name <span style="font-weight: bold;">formInfo</span>. Then we fetch the values from the firstName and lastName fields and store them to properties of the formInfo object. Notice we're taking advantage of id attributes again--one of jQuery's strong suits. Finally, we call the returnResponse() function, this time with the variable formInfo as its argument.<br /><pre><br /><span style="color: rgb(0, 102, 0);"> function returnResponse(fI){</span><br /><span style="color: rgb(0, 102, 0);"> $("#formDiv").remove();</span><br /><span style="color: rgb(0, 102, 0);"> ' + callbackFunc + '(fI);</span><br /><span style="color: rgb(0, 102, 0);"> }</span><br /><span style="color: rgb(0, 102, 0);"></script></span><br /></pre>The last part is the definition for that returnResponse() function. All it does is remove the formDiv (the popup) from the DOM, and then do something with a variable called <span style="font-weight: bold;">callbackFunc</span>. Let's take a closer look at that.<br /><br />Remember this is all in the context of building that string variable called <span style="font-weight: bold;">s</span>. So that line with the callbackFunc variable is really building some text that uses a value stored in the callbackFunc variable. Looking back at the top of the code, the function signature for showPopup() specifies an argument called callbackFunc:<br /><pre><span style="font-size:85%;"><span style="color: rgb(0, 153, 0);">function showPopup(callbackFunc) {</span></span></pre>This is where we get that value. In the calling page, the showPopup() function is called with an argument of <span style="font-weight: bold;">'processData'</span>. So the script is actually building a line that looks like this:<br /><pre><br /><span style="color: rgb(0, 102, 0);">processData(fI);</span><br /></pre><br />This is how the script triggers the callback function. Of course, the <span style="font-weight: bold;">fI</span> variable is just passing along what was passed into the returnResponse function--either the string "Cancelled" in one case, or the object <span style="font-weight: bold;">formInfo</span> in the other.<br /><br />That's it. The callback function can now deal with the response data in any way it wants. In this example, we're just plugging the values into a string and displaying an alert box to show how it works. In an application, we might be doing something like plugging the new values into a list, etc.<br /><br />Have fun!Jeffhttp://www.blogger.com/profile/00213799011122065919noreply@blogger.com1tag:blogger.com,1999:blog-2313269921880066044.post-74159350376297813682008-08-26T21:30:00.008-04:002008-08-26T22:13:45.618-04:00A Popup FormToday's tidbit is a way to inject a popup form into a page and use its form fields on the page once the form has been submitted. Of course, once submitted, the form should destroy itself. These pics show the sequence of events:<br /><br />1. The initial page with just a button<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_i4Z0R0ZArEA/SLS2b5EAgPI/AAAAAAAAAA0/ZJVRyz8Bl7M/s1600-h/jsPopup1.png"><img style="cursor: pointer;" src="http://2.bp.blogspot.com/_i4Z0R0ZArEA/SLS2b5EAgPI/AAAAAAAAAA0/ZJVRyz8Bl7M/s320/jsPopup1.png" alt="" id="BLOGGER_PHOTO_ID_5239012856829083890" border="0" /></a><br /><br />2. Click the button and the form pops up:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_i4Z0R0ZArEA/SLS2xw8ZEuI/AAAAAAAAAA8/B_W-yvgAbT0/s1600-h/jsPopup2.png"><img style="cursor: pointer;" src="http://3.bp.blogspot.com/_i4Z0R0ZArEA/SLS2xw8ZEuI/AAAAAAAAAA8/B_W-yvgAbT0/s320/jsPopup2.png" alt="" id="BLOGGER_PHOTO_ID_5239013232606778082" border="0" /></a><br /><br />3. Fill out the form:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_i4Z0R0ZArEA/SLS3L_uaUtI/AAAAAAAAABE/KHUlLodvz1A/s1600-h/jsPopup3.png"><img style="cursor: pointer;" src="http://4.bp.blogspot.com/_i4Z0R0ZArEA/SLS3L_uaUtI/AAAAAAAAABE/KHUlLodvz1A/s320/jsPopup3.png" alt="" id="BLOGGER_PHOTO_ID_5239013683251270354" border="0" /></a><br /><br />4. Click Save and the form data returns to the page. Here we're just using an alert() to show that the data made the trip back to the controlling page:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_i4Z0R0ZArEA/SLS3VHHjuxI/AAAAAAAAABM/OnneUepBmcg/s1600-h/jsPopup4.png"><img style="cursor: pointer;" src="http://2.bp.blogspot.com/_i4Z0R0ZArEA/SLS3VHHjuxI/AAAAAAAAABM/OnneUepBmcg/s320/jsPopup4.png" alt="" id="BLOGGER_PHOTO_ID_5239013839854615314" border="0" /></a><br /><br />This technique can be used for all kinds of small popup forms. You could create your own message popup that looks nicer than the alert() box, for example.<br /><br />Here's the calling page for the example, which just fetches a new employee's first and last names:<br /><pre><span style="font-size:85%;"><span style="color: rgb(0, 153, 0);"><html></span><br /><span style="color: rgb(0, 153, 0);"><head></span><br /><span style="color: rgb(0, 153, 0);"> <title>Popup Form Test</title></span><br /><span style="color: rgb(0, 153, 0);"> <script type="text/javascript" src="../../jquery/jquery.js"></script></span><br /><span style="color: rgb(0, 153, 0);"> <script type="text/javascript" src="popupFormFunction.js"></script></span><br /><span style="color: rgb(0, 153, 0);"> <script type="text/javascript"></span><br /><span style="color: rgb(0, 153, 0);"> function processData(formData){</span><br /><span style="color: rgb(0, 153, 0);"> s = formData != "Cancelled" ? formData.firstName + ' ' + formData.lastName : formData;</span><br /><span style="color: rgb(0, 153, 0);"> alert(s);</span><br /><span style="color: rgb(0, 153, 0);"> }</span><br /><span style="color: rgb(0, 153, 0);"> </script></span><br /><span style="color: rgb(0, 153, 0);"></head></span><br /><span style="color: rgb(0, 153, 0);"><body> </span><br /><span style="color: rgb(0, 153, 0);"> <input type="button" id="btnShowForm" value="New Employee" onclick="showPopup('processData');" /></span><br /><span style="color: rgb(0, 153, 0);"></body></span><br /><span style="color: rgb(0, 153, 0);"></html></span></span><br /></pre>All this page does is show a button. When you click the button, it pops up the form using the showPopup() function. When the form is submitted, it runs the callback function specified in the showPopup() argument--in this case that function is processData().<br /><br />Here's the content of the popupFormFunction.js file:<br /><pre><br /><span style="font-size:85%;"><span style="color: rgb(0, 153, 0);">function showPopup(callbackFunc) {</span><br /><span style="color: rgb(0, 153, 0);"> s = '';</span><br /><span style="color: rgb(0, 153, 0);"> s += '<style>';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' #formDiv {';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' position: absolute;';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' top: 100px;';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' left: 100px;';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' background-color: #D9E8D7;';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' color: #33532F;';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' border: 1px solid #33532F;';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' padding: 12px 6px 0px 6px;';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' font-family: Tahoma, Helvetica, sans-serif;';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' font-size: 9pt; ';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' text-align: center; ';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' }';</span><br /><span style="color: rgb(0, 153, 0);"> s += '</style>';</span><br /><span style="color: rgb(0, 153, 0);"> s += '';</span><br /><span style="color: rgb(0, 153, 0);"> s += '<div id="formDiv">';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' <strong>New Employee</strong><br /><br />';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' <form name="newEmployeeForm" id="newEmployeeForm" method="post">';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' First Name: <input id="firstName" name="firstName" type="text" /><br />';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' Last Name: <input id="lastName" name="lastName" type="text" /><br />';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' <input type="submit" name="btnSave" id="btnSave" value="Save"><input type="button" name="btnCancel" id="btnCancel" value="Cancel">';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' </form>';</span><br /><span style="color: rgb(0, 153, 0);"> s += '</div>';</span><br /><span style="color: rgb(0, 153, 0);"> s += '';</span><br /><span style="color: rgb(0, 153, 0);"> s += '<script type="text/javascript">';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' formInfo = "";';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' $("#btnCancel").click(function(){';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' returnResponse("Cancelled");';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' });';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' $("#newEmployeeForm").submit(function(){';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' formInfo = new Object;';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' formInfo.firstName = $("#firstName").val();';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' formInfo.lastName = $("#lastName").val();';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' returnResponse(formInfo);';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' });';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' function returnResponse(fI){';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' $("#formDiv").remove();';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' ' + callbackFunc + '(fI);';</span><br /><span style="color: rgb(0, 153, 0);"> s += ' }';</span><br /><span style="color: rgb(0, 153, 0);"> s += '</script>';</span><br /><span style="color: rgb(0, 153, 0);"> $("body").append(s);</span><br /><span style="color: rgb(0, 153, 0);">}</span><br /></span></pre><br /><br />I put the HTML, CSS, and JavaScript for the form all into a string variable, then inject that HTML into the DOM. This can be done in any of a variety of ways--that stuff could be an HTML file that we fetch via HTTPRequest, for example. The way I have it here is just a nice concise way to represent the technique.<br /><br />Deconstruction to follow tomorrow--there are lots of fun little techniques to be mined from this example.Jeffhttp://www.blogger.com/profile/00213799011122065919noreply@blogger.com1tag:blogger.com,1999:blog-2313269921880066044.post-48461909462012136652008-08-25T16:20:00.000-04:002008-08-25T19:13:59.274-04:00Totaling Table Columns DeconstructedSo the last post provided a function that calculates totals based on classes placed on rows in a table. This post will go through that function line-by-line so all its secrets are revealed. If you're already a jQuery pro, you can skip these "Deconstructed" posts, as they're really aimed at a detailed understanding of the code.<br /><br />Now, before we even start, there's a piece of code that's not mentioned. It's the call to the jQuery library, without which all is for naught. It should look like this:<br /><br /><span style="font-size:85%;"><span style="color: rgb(0, 153, 0);"><script type="text/javascript" src="../js/jquery.js"></script></span><br /></span><br />The part that will change on your local file is the src attribute. The value there needs to be whatever the path is to your local jQuery library. With that in place, we're ready to move on. Let's get to it.<br /><br /><span style="color: rgb(0, 153, 0);font-size:85%;" >function totalTableSubRows(tableID, totalClass, dataClass, columnNumber) {</span><br /><br />The first line of the function is its signature. It specifies that the function takes four arguments. They are:<br /><span style="font-weight: bold;">tableID:</span> the HTML id of the table to use<br /><span style="font-weight: bold;">totalClass:</span> the CSS class of the row where totals should be placed<br /><span style="font-weight: bold;">dataClass:</span> the CSS class of rows where data is located<br /><span style="font-weight: bold;">columnNumber:</span> the column number (left to right, starting at 1) where the data is located<br /><br />Now we get into the meat of the thing. First, some variables are set:<br /><br /> <span style="font-size:85%;"><span style="color: rgb(0, 153, 0);">tableSelector = "#" + tableID;</span><br /><span style="color: rgb(0, 153, 0);"> totalSelector = "." + totalClass;</span><br /><span style="color: rgb(0, 153, 0);"> dataSelector = "." + dataClass;</span><br /><span style="color: rgb(0, 153, 0);"> columnIndex = columnNumber - 1;</span><br /></span> <br />The first three assignments take the arguments passed into the function and turn them into the selector strings we're going to need in order to work with jQuery. The hash (#) is the symbol for matching an HTML id attribute, so it gets prepended to the tableID. The dot (.) is the symbol for matching an HTML class attribute, so it gets prepended to the class names for the totals row and the data rows.<br /><br />The fourth assignment adjusts the column number so that it uses JavaScript-friendly zero-based indexing, instead of the more human-friendly 1-based indexing. That is, when we count the columns in the table, we naturally start with 1 at the leftmost column, and count to the right. So we would say the second column's index is 2. But JavaScript calls the first thing 0, so the second column would be 1, and so forth. Subtracting 1 from the argument allows us to use human-friendly counting, while the function uses JavaScript-friendly counting. Everybody's happy.<br /><br /><span style="font-size:85%;"><span style="color: rgb(0, 153, 0);"> $(tableSelector + ' tr' + totalSelector).each(function(){</span><br /></span><br />Now starts the jQuery. The $ symbol is an abbreviation for "the jQuery object". So <span style="font-weight: bold;">$()</span> is the same as saying <span style="font-weight: bold;">jQuery()</span>. We'll be seeing this a lot.<br /><br />jQuery's argument is called a selector. The selector causes jQuery to return a JavaScript object of type jQuery which contains every element in the DOM that matches the selector. jQuery methods can then act on the members of this return set.<br /><br />The first selector combines the tableSelector and totalSelector variables, separated by space-tr-space. Since the tableSelector specifies the table's ID, and the totalSelector specifies the class of the totals row(s), this combination says, "select all td elements with a class equal to the value of totalSelector that are descendants of the element whose ID is equal to the value of tableSelector".<br /><br />The .each() method says "do what's inside my parens for each member of the selected jQuery object." So what's inside its parens? Turns out, a good bit.<br /><br />In JavaScript, "function" is a first-class datatype. That just means that we can specify a function as a set of instrutions that can then be passed around assigned by its name. If we don't need to use a name, we can use the so-called "anonymous function" construct, as seen here. Notice there's no function name after the keyword <span style="font-weight: bold;">function</span>. We're just creating a function on the fly and handing it as an argument to the each() method. By doing this, we've assigned behavior that will be performed for each member of the return set (in this case, all the total rows).<br /><br /><span style="font-size:85%;"><span style="color: rgb(0, 153, 0);"> $(this).children("td:eq(" + columnIndex + ")").html(0);</span><br /></span><br />Now we have another jQuery selector. This one is based on the <span style="font-weight: bold;">this</span> keyword. Note that it is not within quotes. To jQuery, <span style="font-weight: bold;">this</span> means "the element referred to by each() at this time". In this case it means "this total row".<br /><br />The children() method means "look for the selector in my argument in the elements that are direct children of the return set". At this point, the return set is a single row of the table (specified by <span style="font-weight: bold;">$(this)</span>). The selector passed to it uses the :eq() filter to find a specific td element. In this case, it's finding the cell specified by the <span style="font-weight: bold;">columnIndex</span> variable.<br /><br />The next part of the line shows an example of jQuery <span style="font-style: italic;">chaining</span>. Every jQuery method returns the same return set for which it is a method. This means that methods can be strung together in a chain, with each method operating in turn on the return set. This is the case with the html() method at the end of this line. It's simply setting the HTML inside the selected td element to 0.<br /><br />So this line is simply saying "Set all the td's in the specified column of each total row to 0."<br /><br /><span style="font-size:85%;"><span style="color: rgb(0, 153, 0);"> total = 0;</span><br /></span><br />Now we initialize the <span style="font-weight: bold;">total</span> variable to zero.<br /><br /><span style="font-size:85%;"><span style="color: rgb(0, 153, 0);"> $(this).nextAll().each(function(){</span><br /></span><br />And use another jQuery selector. Again, we're using this to operate on each total row (we're still inside the function for the each() method that selected total rows, remember). The nextAll() method says "select all sibling elements that come after the specified element". And each() once again allows us to assign behavior to each of those siblings.<br /><br /><span style="font-size:85%;"><span style="color: rgb(0, 153, 0);"> if($(this).hasClass(dataClass)){</span><br /></span><br />Now some conditional logic: if the selected element (row, in this case) has the value specified by <span style="font-weight: bold;">dataClass</span> as its class attribute, we'll do the next four lines.<br /><br /><span style="font-size:85%;"><span style="color: rgb(0, 153, 0);"> thisVal = $(this).children("td:eq(" + columnIndex + ")").html() * 1;</span><br /><span style="color: rgb(0, 153, 0);"> if (!isNaN(thisVal)) {</span><br /><span style="color: rgb(0, 153, 0);"> total += thisVal;<br /> }<br /></span></span><br />The first line pulls the value out of the specified cell (td) and makes sure JavaScript will treat the number as a value by multiplying it by 1. If that multiplication doesn't result in "NaN" (i.e. the cell contained a number), that number is added to the total.<br /><br />If the row doesn't have the dataClass assigned as its class, then we'll do the next rows:<br /><br /><span style="font-size:85%;"><span style="color: rgb(0, 153, 0);"> } else {</span><br /><span style="color: rgb(0, 153, 0);"> if($(this).hasClass(totalClass)){</span><br /><span style="color: rgb(0, 153, 0);"> return false;</span><br /><span style="color: rgb(0, 153, 0);"> }</span><br /><span style="color: rgb(0, 153, 0);"> }</span><br /></span><br />We don't want to do anything, unless run across a row that has the class specified in the totalClass variable. In that case, we want to quit adding values to the total, because we're done with the children of the current total row. This is what the <span style="font-style: italic;">return false</span> statement does.<br /><br />And this is the end of the function definition inside the each() after the nextAll():<br /><br /><span style="font-size:85%;"><span style="color: rgb(0, 153, 0);"> });</span></span><br /><br /><br /> $(this).children("td:eq(" + columnIndex + ")").html(total);<br /><br />Now we're back in the each() function of the original selector (the total row), so we just select the child td element in the desired column (<span style="font-weight: bold;">:eq()</span> with the columnIndex variable) and assign the calculated total as its HTML content (<span style="font-weight: bold;">html()</span>).<br /><br />This is a good place to point out the dual nature of many jQuery methods. These methods at as both "getters" and "setters". If no argument is given, the method returns the requested value. If an argument is specified, the method sets the specified value. So, in this example, we've used the html() function to both set the value and fetch the value of some td elements.<br /><br /><span style="font-size:85%;"><span style="color: rgb(0, 153, 0);"> });</span><br /><span style="color: rgb(0, 153, 0);"> }</span><br /></span><br />Finally, we're just closing out the function that's inside the each() method, the each() method itself, and the totalTableSubRows function.<br /><br />To call this function, we just need to specify the desired arguments. As we saw in the previous post, those calls look like this:<br /><br /><span style="font-size: 85%;"><span style="color: rgb(0, 153, 0);">totalTableSubRows("myTable","regionRow", "storeRow",2);</span><br /><span style="color: rgb(0, 153, 0);">totalTableSubRows("myTable","totalsRow", "storeRow",2);</span><br /><br />The first one says, "Put the totals of storeRows' second columns in their respective regionRows".<br />The next one says, </span><span style="font-size: 85%;">"Put the totals of storeRows' second columns in their respective totalsRows".<br /><br />Happy jQuerying!<br /><br /></span>Jeffhttp://www.blogger.com/profile/00213799011122065919noreply@blogger.com2tag:blogger.com,1999:blog-2313269921880066044.post-42242086576940094732008-08-25T15:28:00.000-04:002008-08-25T16:16:03.755-04:00Totaling Table ColumnsMany of the applications I deal with are financial in nature, and often have a requirement to provide subtotals and totals of column rows. This can be a daunting exercise if attacked from a DOM perspective, but it's pretty easy with jQuery. Take a look at this table:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_i4Z0R0ZArEA/SLMSifkX9OI/AAAAAAAAAAQ/1JQhWEGKt_Y/s1600-h/regionSalesTable.png"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_i4Z0R0ZArEA/SLMSifkX9OI/AAAAAAAAAAQ/1JQhWEGKt_Y/s320/regionSalesTable.png" alt="" id="BLOGGER_PHOTO_ID_5238551175360935138" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />We want to be able to total the stores' sales figures for each region, then provide a grand total up a the top. To make this easy, I assigned an ID to the table, and a class to reach row depending on its type. Here's the table code:<br /><br /><pre><br /><table id="myTable" border="1"><br /><thead><br /><tr class="headerRow"><br /> <th>Region</th><br /> <th>Sales</th><br /></tr><br /></thead><br /><tbody><br /><tr class="totalsRow"><br /> <td>All</td><br /> <td>0</td><br /></tr><br /><tr class="regionRow"><br /> <td>North</td><br /> <td>0</td><br /></tr><br /><tr class="storeRow"><br /> <td> Boston</td><br /> <td>10</td><br /></tr><br /><tr class="storeRow"><br /> <td> New York</td><br /> <td>20</td><br /></tr><br /><tr class="regionRow"><br /> <td>South</td><br /> <td>0</td><br /></tr><br /><tr class="storeRow"><br /> <td> Charleston</td><br /> <td>40</td><br /></tr><br /><tr class="storeRow"><br /> <td> Atlanta</td><br /> <td>80</td><br /></tr><br /></tbody><br /></table><br /></pre><br /><br />You can see the classes defined for totalsRow, regionRow, and storeRow. Now all we need is a little plumbing to figure out the totals. Here's a function I wrote that will work with any table having figures in columns (that is, no additional markup inside the tags):<br /><br /><pre><br /><script type="text/javascript"><br /> /*<br /> totalTableSubRows()<br /> By Jeff Peters, Aug 2008. Released to the public domain.<br /> Courtesy of jQuery Nuts and Bolts, http:// jquerynab.blogspot.com<br /> */<br /> function totalTableSubRows(tableID, totalClass, dataClass, columnNumber) {<br /> tableSelector = "#" + tableID;<br /> totalSelector = "." + totalClass;<br /> dataSelector = "." + dataClass;<br /> columnIndex = columnNumber - 1;<br /> $(tableSelector + ' tr' + totalSelector).each(function(){<br /> $(this).children("td:eq(" + columnIndex + ")").html(0);<br /> total = 0;<br /> $(this).nextAll().each(function(){<br /> if($(this).hasClass(dataClass)){<br /> thisVal = $(this).children("td:eq(" + columnIndex + ")").html() * 1;<br /> if (!isNaN(thisVal)) {<br /> total += thisVal;<br /> }<br /> } else {<br /> if($(this).hasClass(totalClass)){<br /> return false;<br /> }<br /> }<br /> })<br /> $(this).children("td:eq(" + columnIndex + ")").html(total);<br /> })<br /> }<br /><br /> $(document).ready(function(){<br /> $("#btnCalculate").click(function(){<br /> totalTableSubRows("myTable","regionRow", "storeRow",2);<br /> totalTableSubRows("myTable","totalsRow", "storeRow",2);<br /> });<br /> });<br /></script><br /></pre><br /><br />To make it work , you just call it with the desired parameters. Since we want to sets of calculations--one for the region rows, and one for the totals row, we call the function twice:<br /><br /><blockquote><span style="font-size:85%;"> totalTableSubRows("myTable","regionRow", "storeRow",2);<br />totalTableSubRows("myTable","totalsRow", "storeRow",2);</span><br /></blockquote>The first call goes to myTable, calculates the totals from the storeRow rows under each regionRow row, and returns the total for each regionRow row to that row, with numbers found in the second column. The second call does the same thing, but totals all regionRow rows under the totalsRow. All done.<br /><br />This function is extremely useful if you're injecting rows of data into the table. You can run the function right after a row injection (or deletion), and see the totals stay current.<br /><br />As soon as I can figure out how to get blogspot to allow demo code pages, I'll post this so you can watch a live demo here.Jeffhttp://www.blogger.com/profile/00213799011122065919noreply@blogger.com1tag:blogger.com,1999:blog-2313269921880066044.post-77648013524987167112008-08-25T14:28:00.000-04:002008-08-25T14:33:42.499-04:00First Things FirstOh, no! Not another blog! More junk to follow, etc., etc.<br /><br />That's how I figured you, the audience, might see this little effort. But I hope to make this blog a little bit different by putting first things first.<br /><br />When it comes to developing web apps, the user experience comes first. After all, if the user doesn't like it, it won't be used--so much for the greatest web app in history.<br /><br />In similar fashion, when it comes to blogs about programming, I think what matters is *what* the thing does--how it does it is really secondary (though often very valuable) information.<br /><br />So that's what I intend to do: offer examples of jQuery in action, then take apart the code to see what's under the hood. The first part should appeal to you if you just want a new widget to add to an app; the second part is for those who want to explore jQuery more than they've had a chance to yet.<br /><br />So that's it. Please feel free to drop comments, tell your friends, ask questions, and generally be part of the "thing". We're all friends here.Jeffhttp://www.blogger.com/profile/00213799011122065919noreply@blogger.com0