I have once again given a JavaScript guest lecture to Zach‘s Web Programming class. This year I have taken the liberty of swiping some of Douglas Crockford’s “JavaScript: The Good Parts” presentation for the leading slides.
Here’s the presentation:
I have once again given a JavaScript guest lecture to Zach‘s Web Programming class. This year I have taken the liberty of swiping some of Douglas Crockford’s “JavaScript: The Good Parts” presentation for the leading slides.
Here’s the presentation:
Zach has asked me to give a JavaScript guest lecture in his Web Programming class. We’ll cover: JS basics, node manipulation, DOM traversal, AJAX, JavaScript libraries, and myPlymouth implementations of those topics. Here are the slides (get the .ppt here):
A few resources that are mentioned:
Note: this is an updated talk on the workshop I led two years ago
[[innerindex]]
I gave a talk at SunGard Summit in Anaheim this spring on Plymouth State‘s portal (myPlymouth). There were a number of really great questions that came up following my presentation, one of which is the topic of this post:
When upgrading Plymouth State’s Luminis installation from III to IV, we had to tackle this same issue and after banging my head against the wall a number of times, I found our answer. I wanted to:
All of it was super easy to do, although I must admit I knocked my head against the wall a few times coming up with the solution to the 3rd in that list.
When I sat down to tackle this problem, I knew that the inline JavaScript within nested_tables.xsl was an unforgiving issue – if I wanted to make a change to some of the inline JavaScript, those changes would not be forced upon the users until Luminis decided to let go of its cached nested_tables.xsl.
That didn’t work for me. So I ripped the inline styles out and combined a few JavaScript files into one…called combined.js.
My header within the regularLayout template in nested_tables.xslnow looked something like this:
<head .......> <title>.........</title> <script type="text/javascript" src="/js/clientsniffer.js"></script> <script type="text/javascript" src="/js/util.js"></script> <script type="text/javascript" src="/psu/js/combined.js"></script> <script type="text/javascript" src="/psu/js/behavior.js"></script> <link rel="stylesheet" type="text/css" href="/psu/style.css"/> </head>
The files clientsniffer.js and util.js are SunGard delivered and I did not touch those two. As I mentioned before, I yanked out all the inline JavaScript (provided by SunGard) and dropped that into combined.js along with a number of jQuery code. Our own custom Luminis JavaScript that controls a lot of our Ajax-like functionality in myPlymouth is in behavior.js. And of course, style.css holds the CSS for our portal.
All of these files could now be cached by users’ browsers. Yay. I bounced the development portal and saw my changes in all their glory. Life was good.
Invigorated by my recent success of effectively doing nothing, I grabbed a soda and began tackling the next objective. I had done this numerous times in my PHP applications and it was as simple as placing a version number at the end of the URLs used in the link and script tags. As such:
<head .......> <title>.........</title> <script type="text/javascript" src="/js/clientsniffer.js"></script> <script type="text/javascript" src="/js/util.js"></script> <script type="text/javascript" src="/psu/js/combined.js?v=1.0.0"></script> <script type="text/javascript" src="/psu/js/behavior.js?v=1.0.5"></script> <link rel="stylesheet" type="text/css" href="/psu/style.css?v=1.0.5"/> </head>
Once again, I bounced our portal, saw the changes, and danced around the room. Step 2. Accomplished.
The goal of taming this versioning/cache expiration was to do so without the need for bouncing the portal so I could make changes on the fly without planning for down times. Step 2 – as I detailed above – only gets you so far. With Step 2 in place, I could easily make a change in my CSS file and edit nested_tables.xsl to one-up my version number. But, because nested_tables is cached by Luminis, that wasn’t good enough. Here’s what I came up with:
I removed the script and link tags in the header of the regularLayout template in nested_tables, created a file called load.js, and dropped the homeless script/link tags as document.writes in load.js…as so:
document.write('<script type="text/javascript" src="/js/clientsniffer.js"></script>');
document.write('<script type="text/javascript" src="/js/util.js"></script>');
document.write('<script type="text/javascript" src="/psu/js/combined.js?v=1.0.0"></script>');
document.write('<script type="text/javascript" src="/psu/js/behavior.js?v=1.0.5"></script>');
document.write('<link rel="stylesheet" type="text/css" href="/psu/style.css?v=1.0.5"/>');
This gave me a file with all of my script/link tags and their appropriate versions. However…I couldn’t simply replace all those script/link tags with a script tag that pointed at load.js because load.js itself would be cached by users’ browsers. So this got past the Luminis caching, but not our end users. So I came up with this:
So…I wanted to cache all my sub-files and prevent load.js from caching so that I could version my scripts easily without bouncing the portal. The solution? Yet another file! I called it pre_load.js and it looks something like this:
document.write('<script type="text/javascript" src="/psu/js/load.js?nocache=' + (new Date()).getTime() + '"></script>');
A simple document.write of a script tag with an appended variable based on time in order to prevent caching on the browser side. Yup…load.js is never cached, but it is a small price to pay.
Now my header in the regularLayout template in nested_tables.xsl looks like this:
<head .......> <title>.........</title> <script type="text/javascript" src="/psu/js/pre_load.js"></script> </head>
The set-up is fairly basic but the results just what we were hoping! And all it took was:
To date, we have not had any reported issues with local or server-side caching of our JS/CSS files using this method! You just need to make sure you remember to version your URLs in load.js!
Tonight I led a workshop on JavaScript for some PSU Employees. We discussed JS basics, node manipulation, DOM traversal, AJAX, JavaScript libraries, and myPlymouth implementations of those topics. Here are the slides:
A few resources that were mentioned:
This is a major release for the JavaScript library that I have grown to love. Before I list the new features, it is important to note what functionality has been removed from jQuery.
Thankfully a number of those don’t effect me. I’ll have to comb through my code to get rid of the .gt, .lt, and .eq traversal functions as well as a few of the selectors…but other than that, I’m good to go. To find out more about workarounds for the above removed functionality, check the jQuery 1.2 release notes
Now…on to the good stuff.
I have to say…it is a pretty snazzy release and I’ll begin implementing the new version shortly. w00t.
My hear is exploding with happiness and joy at the existence of Brandon Aaron. He has built a sweet jQuery plugin (Live Query) that reduces complexity in Ajax and general DOM manipulation coding by a great deal (when it comes to applying behaviors). First, let me tell you the problem (if you don’t already know):
Say I build a web application where I want to assign an onClick event to an <a> tag. In jQuery I’d do it like this:
First the HTML:
<a href="another.html" class="another">Grab Another!</a> <ul> <li><a href="whee.html" class="whatever">Bork</a></li> <li><a href="whee.html" class="whatever">Bork</a></li> <li><a href="whee.html" class="whatever">Bork</a></li> </ul>
Now lets do up the JavaScript:
$(document).ready(function(){
$('a.whatever').bind('click',function(){
alert('ZOMG Hai');
return false;
});
});
Simple, right? Yeah. It is. Nothing new. Now…say that I manipulate the DOM and add in another <a> tag with the class “whatever” that I want the same even applied (with or without Ajax, doesn’t matter). Here’s what I would have had to do in the past:
$(document).ready(function(){
$('a.another').bind('click',function(){
$('ul').append('<a href="whee.html" class="whatever">Bork</a>');
$('a.whatever').bind('click',function(){
alert('ZOMG Hai');
return false;
});
return false;
});
});
See that? Kinda complex. Things become quite complex when you begin doing Cross Domain Scripting via Remote JavaScript calls (which is what is heavily used in one of the apps I have done front-end development for).
The Live Query plugin is a beautiful thing as it “auto-magically” binds events to dynamically added elements within the page as they appear! So ALL of that JavaScript from both examples becomes:
$(document).ready(function(){
$('a.whatever').livequery('click',function(){
alert('ZOMG Hai');
return false;
});
$('a.another').bind('click',function(){
$('ul').append('<a href="whee.html" class="whatever">Bork</a>');
return false;
});
});
Yup. That’s it. Bind a livequery event to an element and as elements that match appear on the page…BAM! The event is applied.
There are some more advanced things you can do with the plugin and you can find those out at the Live Query site.
I’m a huge fan and avid user of jQuery and have been extremely impressed by the documentation provided on the jQuery website. The one thing that documentation lacks, however, is really contextual examples that drive home some bare essentials of JavaScripting with the jQuery library. Learning jQuery – a book by Jonathan Chaffer and Karl Swedberg – is an excellent introductory book for those that are thinking about using (or struggling with) jQuery.
jQuery, while a fairly high level JavaScript library is a beautiful thing but can be very daunting to a developer that is new to JavaScripting or is coming from a dissimilar library, being thrust full bore into a ‘new’ way of doing old tricks. (Which jQuery is great at by the way…it makes the new ways super sexy, sleek, and easy). The authors do a great job of explaining what jQuery is and why it is such a powerful tool.
Throughout the book are examples on traversing and manipulating the DOM, event handling, leveraging jQuery’s JS effect capabilities, AJAX, etc; many of which are built off of previously detailed examples, allowing the reader to easily grasp what is going on and why a chunk of code was used.
While I feel this book is primarily an excellent introductory source for diving into the world of JavaScript development with jQuery, the fairly seasoned jQuery user (like myself) may find a trick or two that they hadn’t quite thought of… As I read through, I found a few choice bits that allowed me to make my own code more efficient!
My only real complaint with the book is the index at the back. There are a number of jQuery functions that are discussed within the chapters yet weren’t referenced in the index. A small nitpick, I know, but I’m a sucker for a good index :)
So. Overall, I think the book is a good thing to keep on the bookshelf, whether a you are a jQuery n00b or not. There’s always a co-worker/friend/programming buddy that will want to learn jQuery and what better way to get them rolling on there own than a link to the jQuery docs and a sweet book?
You can get the book here.
[[innerindex]]
This has been a long time coming and I am happy to announce the release of Sexy Comments v1.4! With this version comes a lot of changes…so be sure to read the installation section! Along with simple optimizations and general restructure, the following features are now available:
< ?php sexycomments::show($comments); ?>
< ?php sexycomments::form(); ?>
NOTE: Be sure not to touch the section that generates the form for adding comments! This plugin does not re-create the comment creation form.
A: Ah, yes. That thing. Well, its anatomy looks similar to this (there will be some variation from theme to theme):
< ?php if ($comments) : ?>
<!-- some HTML is typically here -->
< ?php foreach ($comments as $comment) : ?>
<!-- the output HTML of each individual comment -->
< ?php endforeach; /* end for each comment */ ?>
<!--...more HTML -->
< ?php else : // this is displayed if there are no comments so far ?>
< ?php if ('open' == $post->comment_status) : ?>
<!-- typically a blank area or a place with a comment -->
< ?php else : // comments are closed ?>
<!-- closed comments section -->
< ?php endif; ?>
< ?php endif; ?>
A: Yeah. Sorry about that. In this version, the directory structure has changed drastically and Sexy Comments should no longer live in wp-content/plugins/sexycomments.php OR wp-content/plugins/sexycomments/sexycomments.php, but instead it should be in wp-content/plugins/sexy-comments/. Make sure that the plugin is in the correct location of your plugins directory.
A: Along with a directory structure overhaul, this version had a large code overhaul as well. The old function (sexycomments_print) is deprecated but will still work for the time being. I greatly urge you to move over to the new function call sexycomments::show($comments) as that is the new *impoved* function.
After a long wait, jQuery 1.1.3 has been released! (Download it at the jQuery site) When I first adopted jQuery a year ago, the library boasted both faster speeds and smaller size than any other JavaScript Ajax/DOM tool. With the release of jQuery’s version 1.1.2, a number of jQuery’s operations became very slow and inefficiencient, as evidenced by MooTool’s SlickSpeed CSS Selector Test (found via Ajaxian) which crept up a few weeks ago.
This new release boasts an 800% speed improvement with a number of its selectors along with various enhancements across the board! The selector speed boost makes me one happy camper. Check out the enhancements as it compares to 1.1.2:
| Browser | jQuery 1.1.2 | jQuery 1.1.3 | % Improvement |
|---|---|---|---|
| IE 6 | 4890ms | 661ms | 740% |
| Firefox 2 | 5629ms | 567ms | 993% |
| Safari 2 | 3575ms | 475ms | 753% |
| Opera 9.1 | 3196ms | 326ms | 980% |
| Average improvement: | 867% | ||
And here’s how it now stacks up against the SlickSpeed test:
| Browser | Prototype | jQuery | Mootools | Ext | Dojo |
|---|---|---|---|---|---|
| IE 6 | 1476ms | 661ms | 1238ms | 672ms | 738ms |
| Firefox 2 | 219ms | 567ms | 220ms | 951ms | 440ms |
| Safari 2 | 1568ms | 475ms | 909ms | 417ms | 527ms |
| Opera 9.1 | 220ms | 326ms | 217ms | 296ms | 220ms |
In addition to the speed enhancements, there were several other notable things:
Additionally, the jQuery team has addressed 80+ bugs and has roadmapped out the next two releases (v1.1.4 and v1.2). To check out the full jQuery 1.2 roadmap, go here.
The jQuery 1.1a has been released today by the jQuery team! Its important to note that this is an alpha version before you go out and install it in a production environment, but the jQuery team asks that people give it a round of testing prior to the release this weekend.
The “Quick and Dirty” on v1.1:
With this release come a lot of API changes:
Firstly, :nth-child() now starts at 1, instead of 0.
A number of methods have been re-organized/re-named. Here’s the translation of old to new functions:
| Old Way (1.0.x) | New Way (1.1) |
|---|---|
| .ancestors() | .parents() |
| .width() | .css(”width”) |
| .height() | .css(”height”) |
| .top() | .css(”top”) |
| .left() | .css(”left”) |
| .position() | .css(”position”) |
| .float() | .css(”float”) |
| .overflow() | .css(”overflow”) |
| .color() | .css(”color”) |
| .background() | .css(”background”) |
| .id() | .attr(”id”) |
| .title() | .attr(”title”) |
| .name() | .attr(”name”) |
| .href() | .attr(”href”) |
| .src() | .attr(”src”) |
| .rel() | .attr(”rel”) |
| .oneblur(fn) | .one(”blur”,fn) |
| .onefocus(fn) | .one(”focus”,fn) |
| .oneload(fn) | .one(”load”,fn) |
| .oneresize(fn) | .one(”resize”,fn) |
| .onescroll(fn) | .one(”scroll”,fn) |
| .oneunload(fn) | .one(”unload”,fn) |
| .oneclick(fn) | .one(”click”,fn) |
| .onedblclick(fn) | .one(”dblclick”,fn) |
| .onemousedown(fn) | .one(”mousedown”,fn) |
| .onemouseup(fn) | .one(”mouseup”,fn) |
| .onemousemove(fn) | .one(”mousemove”,fn) |
| .onemouseover(fn) | .one(”mouseover”,fn) |
| .onemouseout(fn) | .one(”mouseout”,fn) |
| .onechange(fn) | .one(”change”,fn) |
| .onereset(fn) | .one(”reset”,fn) |
| .oneselect(fn) | .one(”select”,fn) |
| .onesubmit(fn) | .one(”submit”,fn) |
| .onekeydown(fn) | .one(”keydown”,fn) |
| .onekeypress(fn) | .one(”keypress”,fn) |
| .onekeyup(fn) | .one(”keyup”,fn) |
| .oneerror(fn) | .one(”error”,fn) |
| .unblur(fn) | .unbind(”blur”,fn) |
| .unfocus(fn) | .unbind(”focus”,fn) |
| .unload(fn) | .unbind(”load”,fn) |
| .unresize(fn) | .unbind(”resize”,fn) |
| .unscroll(fn) | .unbind(”scroll”,fn) |
| .ununload(fn) | .unbind(”unload”,fn) |
| .unclick(fn) | .unbind(”click”,fn) |
| .undblclick(fn) | .unbind(”dblclick”,fn) |
| .unmousedown(fn) | .unbind(”mousedown”,fn) |
| .unmouseup(fn) | .unbind(”mouseup”,fn) |
| .unmousemove(fn) | .unbind(”mousemove”,fn) |
| .unmouseover(fn) | .unbind(”mouseover”,fn) |
| .unmouseout(fn) | .unbind(”mouseout”,fn) |
| .unchange(fn) | .unbind(”change”,fn) |
| .unreset(fn) | .unbind(”reset”,fn) |
| .unselect(fn) | .unbind(”select”,fn) |
| .unsubmit(fn) | .unbind(”submit”,fn) |
| .unkeydown(fn) | .unbind(”keydown”,fn) |
| .unkeypress(fn) | .unbind(”keypress”,fn) |
| .unkeyup(fn) | .unbind(”keyup”,fn) |
| .unerror(fn) | .unbind(”error”,fn) |
What’s more? Well, the jQuery team will be posting throughout the week on all the cool new things you can do with jQuery 1.1. I’m looking forward to seeing the changes! Oh, with regards to changes, its important to note with that list of functions above…the old method will no longer work come v1.1. To keep those functions in use, a ‘helper’ library will need to be used…chances are that won’t be available until the 1.1 final.
While at The Ajax Experience in October, I attended a presentation who spoke of the 3 C’s (Combine, Compress, Cache) for Ajax development. In the Compress section I was introduced to the beauty of JSMin!
What is it? Well, shut up and I’ll tell you.
Quoting Douglas Crockford (the creator of JSMin):
JSMin is a filter which removes comments and unnecessary whitespace from JavaScript files. It typically reduces filesize by half, resulting in faster downloads. It also encourages a more expressive programming style because it eliminates the download cost of clean, literate self-documentation.
As I’ve been creating more complex Javascript applications, the file size has been increasing (although the size is greatly reduced, thanks to jQuery). And, as a careful programmer should, I place comments all over my Javascript code so I don’t draw too many blanks while updating/debugging…well, those comments tend to bloat the file size, as does the whitespace. The stripping of those elements alone has dropped the file-size of a number of my scripts by 40-50%! Thats huge. What previously was an 8K file goes down to 4K. Awesome.
If you’re curious what JSMin does to your code, here’s an example that Douglas gives:
Before
// is.js
// (c) 2001 Douglas Crockford
// 2001 June 3
// is
// The -is- object is used to identify the browser. Every browser edition
// identifies itself, but there is no standard way of doing it, and some of
// the identification is deceptive. This is because the authors of web
// browsers are liars. For example, Microsoft's IE browsers claim to be
// Mozilla 4. Netscape 6 claims to be version 5.
var is = {
ie: navigator.appName == 'Microsoft Internet Explorer',
java: navigator.javaEnabled(),
ns: navigator.appName == 'Netscape',
ua: navigator.userAgent.toLowerCase(),
version: parseFloat(navigator.appVersion.substr(21)) ||
parseFloat(navigator.appVersion),
win: navigator.platform == 'Win32'
}
is.mac = is.ua.indexOf('mac') >= 0;
if (is.ua.indexOf('opera') >= 0) {
is.ie = is.ns = false;
is.opera = true;
}
if (is.ua.indexOf('gecko') >= 0) {
is.ie = is.ns = false;
is.gecko = true;
}
After
var is={ie:navigator.appName=='Microsoft Internet Explorer',java:navigator.javaEnabled(),ns:navigator.appName=='Netscape',ua:navigator.userAgent.toLowerCase(),version:parseFloat(navigator.appVersion.substr(21))||parseFloat(navigator.appVersion),win:navigator.platform=='Win32'}
is.mac=is.ua.indexOf('mac')>=0;if(is.ua.indexOf('opera')>=0){is.ie=is.ns=false;is.opera=true;}
if(is.ua.indexOf('gecko')>=0){is.ie=is.ns=false;is.gecko=true;}
As you can see…the result is not easily read so you’ll want to keep your original script around in the event that editing is needed. Super cool. So how do you get it? Well…there’s a number of languages that JSMin logic has been ported to: zip file containing
an MS-DOS.exe file, or you can get the C source code and build it yourself. Now in C# and Java and JavaScript and Perl and PHP and Python and Ruby.
If you haven’t thought about Javascript compression yet, you might want to start. Try it out…you’ll be happy you did. Oh, and if you are curious: the Javascript implementation of JSMin is my favorite as it gives some excellent feedback and comment options on compression.
John Resig over at jQuery has announced the release of jQuery 1.0.4 to the public! As usual, there are bug fixes…plus a bit more. His focus for this patch was adding improvements to jQuery’s Ajax functionality. Below is a list of all the updates:
Example: Add extra headers to an Ajax request using beforeSend
$.ajax({
type: "POST",
url: "/files/add/",
beforeSend: function(xhr) {
xhr.setRequestHeader( "Content-type", "text/plain" );
},
data: "This is the contents of my text file."
});
Example: Perform a synchronous Ajax request.
// Get the HTML of a web page and save it
// to a variable (the browser will freeze until the
// entire request is completed).
var html = $.ajax({
type: "GET",
url: "test.html",
async: false
}).responseText;
// Add the HTML into the page
$("#list").html( html );
Example: Sending a JavaScript object using processData.
// The data to send to the server
var params = {
name: "John",
city: "Boston"
};
$.ajax({
type: "POST",
url: "/user/add/",
processData: params
});
Example: Aborting an Ajax request after a specific delay in time.
// Perform a simple Ajax request
var req = $.ajax({
type: "GET",
url: "/user/list/",
success: function(data) {
// Do something with the data...
// Then remove the request.
req = null;
}
});
// Wait for 5 seconds
setTimeout(function(){
// If the request is still running, abort it.
if ( req ) req.abort();
}, 5000);
Example: Add extra headers to all Ajax requests using the ajaxSend event.
$(document).ajaxSend(function(xhr){
xhr.setRequestHeader("X-Web-Request", "MySite.com");
});
Example: Prevent any POST requests that are sending too much data.
$(document).ajaxSend(function(xhr,options){
if ( options.type == "POST" && options.data.length > 1024 )
xhr.abort();
});
Example: Show a special message for requests submitted using an Ajax POST.
$("#dataSent").ajaxSend(function(xhr,options){
if ( options.type == "POST" )
$(this).show();
});
Example: Have a tooltip follow a user’s mouse around the page.
$(document).mousemove(function(e){
$("#mousetip").css({
top: e.pageY + "px",
left: e.pageX + "px"
});
});
While at The Ajax Experience I noticed a tool that a few of the speakers made use of that was missing from my arsenal. The tool? JavaScript Shell.
This little beauty, once you’ve added the bookmark to your browser allows you to open a JavaScript Shell for any page you happen to be on! The shell lets you enter JavaScript from command-line to manipulate the page, trigger functions, analyze properties, etc. All libraries that the site has loaded are available within the Shell…so, if you use jQuery or some other toolkit, all defined functions and plugins are usable.
Here’s some features and pre-defined functions from the JavaScript Shell site
Features
- You can enter statements and expressions at the same prompt.
- The result of each non-void statement or expression is shown.
- User-defined variables.
- b = document.body
- User-defined functions.
- function f() { return 5; }
- JavaScript error messages are shown in red.
- Previous statements and expressions are available through Up and Down arrow keys.
- Tab completion.
- Multiline input (Shift+Enter to insert a line break).
- If the shell is opened using a bookmarklet, JavaScript typed into the shell runs in the context of the original window.
- Works well in Firefox, mostly works in Opera 8 and in IE 6 for Windows.
Built-in functions
- ans: the result of the previous expression.
- print(expr): prints expr on its own line.
- for(i = 0; i < 6; ++i) print(i * i)
- pr(expr): prints and returns its input, so you can use it to print intermediate results in the middle of an expression.
- function fact(n) { return n>0 ? pr(n*fact(n-1)) : 1 }
- blink(node) or Alt+B: makes a node blink for a second.
- blink(document.links[3])
- props(obj) or Alt+P: lists the methods and fields of an object.
- props(document.body)
- In Firefox, props also shows which properties belong to the object itself and which belong to objects in its prototype chain.
I’m a fan :D
After my excitement about jQuery since The Ajax Experience, one of my fellow developers at PSU has been checking the toolkit out. In her searches for documentation found Visual jQuery, a nice graphical/textual categorized API for the jQuery toolkit! Its a pretty snazzy learning tool if you aren’t already familiar with all the functions jQuery has to offer (found in the jQuery API).
I’ll be using Visual jQuery to explore to toolkit and see what it has to offer and using the JQuery API for quick syntax lookup.
Oh, and on a side note, the people over at Visual jQuery have begun a jQuery magazine in pdf format…pretty neat-o.
I went to The Ajax Experience with high expectations of catching some great tips regarding development in an Ajax environment. At the same time, I was sure of my previous decision with the use of Prototype and Script.aculo.us was as good as it gets (without diving into the widgetized world…e.g. Dojo). I attended John Resig‘s presentation on jQuery and I became a convert.
John’s presentation was less of a presentation and more of a Q&A Demonstration, which suited me fine. As soon as I knew where to download the code, I popped open my laptop and started fiddling around with the toolkit – passively paying attention to the questions and answers, as they tended to be extremely basic questions…you see, jQuery is pretty darn intuitive.
jQuery’s mantra is “Find stuff and do stuff to it”
Yeah, I wasn’t converted because jQuery was the first toolkit to support chaining and that it executes it nicely. Nor was I converted because of its extensive plugin library. Nope. My conversion was the effecient findability of elements within the DOM! This is what really makes jQuery ballsy. The toolkit was built with findability in mind using already established standards! jQuery fully supports CSS1, CSS2, CSS3, and basic XPath when hunting for elements. For example:
Lets start with something simple:
Say I wanted to find all elements within the page that had the class: bork and hide them, I’d do:
$('.bork').hide();
Alright, say I wanted to find all anchor tags with the target set to _blank and add the class whee to it:
$('a[@target=_blank]').addClass('whee');
Now, lets say I want to find all anchor tags with the target set to _blank and add the class whee to them AND append (opens in a new window) as a sibling to the link itself.
$('a[@target=_blank]').each(
function(){
$(this).addClass('whee');
$(this).after('(Opens in a new window)');
}
);
Now, if I knew I was going to use the above a whole lot all over hell’s half acre, I could create a jQuery plugin that can be chained! Here’s how I’d create that feature and allow for the passing of class name:
jQuery.fn.opensInNewWindow = function(classname){
return this.each(
function(){
$(this).addClass(classname);
$(this).after('(Opens in a new window)');
}
);
};
Now, when I want to put Opens in a new window on a series of elements, I can do so with my newly created plugin:
$('a[@target=_blank]').opensInNewWindow('whee');
//I can do this for ANY element I want even if it isn't a link
$('span.bork').opensInNewWindow('zomg');
$('div#w00t ul.nav').opensInNewWindow('roflcopter');
Now, to make use of the chainability, you can write the plugin more simply than what I did up above. You can do this: (thanks to malsup, a commenter on this article)
jQuery.fn.opensInNewWindow = function(classname){
return this.each(
function(){
$(this).addClass(classname).after('(Opens in a new window)');
}
);
};
Cake walk. As your proficiency in finding objects within a page increases, your code will become shorter.
jQuery currently has a very active community and mailing list (averaging at about 90 posts per day) so if you have questions regarding the toolkit, you can become a member and ask away… In addition, there’s a jQuery blog where John posts comparison code showing the difference between jQuery and other available toolkits. (here’s a Zebra striping example)
If you are still on the hunt for a JavaScript toolkit for Ajax, DOM manipulation, etc or you find your toolkit of choice too clunky, give jQuery a shot. You’ll be pleased with the results.