關(guān)鍵字:   jQuery    

這份指南是對(duì)jQeury庫(kù)的介紹,它需要對(duì)JavaScript和文檔對(duì)象模型(DOM)有基本的了解。它從零開(kāi)始講解并解釋必要的細(xì)節(jié)。
該指南講到了一個(gè)簡(jiǎn)單的hello world例子,selector和event基礎(chǔ),AJAX,F(xiàn)X以及使用和創(chuàng)作plugins。
這份指南不包含"click me"例子,只提供"copy me"代碼的意圖是激發(fā)你來(lái)自己嘗試?yán)印opy一個(gè)例子,看看它做什么,并修改它。

目錄
1 Setup
2 Hello jQuery
3 Find me: 使用selectors和events
4 Rate me: 使用Ajax
5 Animate me: 使用Effects
6 Sort me: 使用tablesorter plugin
7 Plug me: 寫你自己的plugins
8 Next steps

Setup
我們首先需要jQuery庫(kù)的copy來(lái)開(kāi)始。最新的版本可以在http://docs.jquery.com/Downloading_jQuery找到,這份指南也提供一個(gè)基本包來(lái)下載。
jQuery Starterkit
下載該文件并解壓,用你最喜歡的編輯器打開(kāi)starterkit.html和custom.js并用瀏覽器打開(kāi)starterkit.html。
現(xiàn)在我們準(zhǔn)備好了開(kāi)始著名的"Hello world"例子的任何事情。
本節(jié)里有意思的鏈接:
jQuery Starterkit
Downloading jQuery

Hello jQuery
當(dāng)我們使用jQuery時(shí)所做的幾乎任何事情都會(huì)讀取或操作文檔對(duì)象模型(DOM),我們需要確認(rèn)一旦DOM準(zhǔn)備好了則我們開(kāi)始添加events等東西。
為了做這件事,我們?yōu)閐ocument注冊(cè)一個(gè)ready事件。

代碼
  1. $(document).ready(function() {  
  2.     // do stuff when DOM is ready  
  3. });  

在該方法里放入一個(gè)alert不會(huì)有多大意義,因?yàn)閍lert不需要DOM成功loaded。所以讓我們嘗試一些更復(fù)雜的東西:當(dāng)點(diǎn)擊該鏈接時(shí)顯示一個(gè)alert。
代碼
  1. $(document).ready(function() {  
  2.     $("a").click(function() {  
  3.         alert("Hello world!");  
  4.     });  
  5. });  

這將在你點(diǎn)擊該鏈接時(shí)顯示alert。
讓我們看看我們做了什么:$("a")是一個(gè)jQuery selector,在這里,它選擇所有的a元素。$本身為jQuery"類"的別名,因此$()構(gòu)建了一個(gè)jQuery對(duì)象。
我們下一步調(diào)用的click()方法為該jQuery對(duì)象的一個(gè)方法。它綁定了一個(gè)click事件到所有被選擇的元素(在這里為一個(gè)單獨(dú)的anchor元素)并當(dāng)事件發(fā)生時(shí)執(zhí)行
提供的方法。
這與下面的代碼類似:
代碼
  1. <a href="" onclick="alert('Hello world')">Link</a>  

區(qū)別非常明顯:我們不需要為每個(gè)單獨(dú)的元素寫一個(gè)onclick。對(duì)結(jié)構(gòu)(HTML)和行為(JS)我們有一個(gè)清晰的分離,就像我們使用CSS來(lái)分離結(jié)構(gòu)和呈現(xiàn)。
了解了這些,我們來(lái)對(duì)selectors和events做一些更多的東西。
本節(jié)里有意思的鏈接:
jQuery Base
jQuery Expressions
jQuery Basic Events

Find me: 使用selectors和events
jQuery提供了兩種方式來(lái)選擇元素。第一種使用作為字符串傳遞給jQuery構(gòu)造器的CSS和XPath選擇器的聯(lián)合(例如$("div > ul a"))。第二種使用jQuery對(duì)象的
一些方法。兩種方式可以聯(lián)合。
我們選擇并修改我們的starterkit里的第一個(gè)排序列表來(lái)嘗試一些選擇器。
我們以選擇列表本身開(kāi)始。列表有一個(gè)ID "orderedlist"。在傳統(tǒng)的JavaScript里,你可以通過(guò)使用document.getElementById("orderedlist")來(lái)使用它。使用
jQuery的話,我們像這樣做:

代碼
  1. $(document).ready(function() {  
  2.     $("#orderedlist").addClass("red");  
  3. });  

starterkit提供了一個(gè)帶有一個(gè)class為"red"的簡(jiǎn)單的添加一個(gè)紅色背景的stylesheet。因此,當(dāng)你在瀏覽器里reload頁(yè)面時(shí),你應(yīng)該看到第一個(gè)ordered list
將擁有一個(gè)紅色背景。第二個(gè)list則沒(méi)變。
現(xiàn)在讓我們添加一些classes到該list的子元素中。
代碼
  1. $(document).ready(function() {  
  2.     $("#orderedlist > li").addClass("blue");  
  3. });  

這將選擇id為orderedlist的元素的所有子li元素并為其添加class "blue"。
現(xiàn)在看看一個(gè)更復(fù)雜的:我們希望當(dāng)用戶hover到該list的最后一個(gè)li元素時(shí)添加和刪除class。
代碼
  1. $(document).ready(function() {  
  2.     $("#orderedlist li:last").hover(function() {  
  3.         $(this).addClass("green");  
  4.     },function() {  
  5.         $(this).removeClass("green");  
  6.     });  
  7. });  

有許多其他類似于CSSXPath語(yǔ)法的選擇器。更多的例子以及一個(gè)所有可得到的表達(dá)式的列表可以在這里找到。
對(duì)每個(gè)可得到的onxxx事件,像onclick,conchange,onsubmit,都有一個(gè)jQuery等價(jià)物。一些其他的事件,像ready和hover,被提供來(lái)作為方法方便某些任務(wù)。
你可以在jQuery Events Documentation里找到完整的事件列表。
使用這些selectors和events你已經(jīng)可以做許多事情,但是這里還有一個(gè)。
代碼
  1. $(document).ready(function() {  
  2.     $("#orderedlist").find("li").each(function(i) {  
  3.         $(this).append(" BAM! " + i);  
  4.     });  
  5. });  

find()允許你對(duì)已經(jīng)選擇的元素做更深的子搜索,因此$("#orderedlist").find("li")幾乎和$("#orderedlist li")一樣。
each()對(duì)每個(gè)元素迭代并允許更多的處理。大多數(shù)方法,像addClass(),自己使用each()。
在這個(gè)例子中,append()用來(lái)在每個(gè)元素的末尾添加一些文本。
另外一個(gè)你經(jīng)常面對(duì)的任務(wù)是在jQuery沒(méi)有cover的DOM元素上調(diào)用方法。考慮一個(gè)你想在通過(guò)AJAX成功提交后reset它的form。
代碼
  1. $(document).ready(function() {  
  2.     // use this to reset a single form  
  3.     $("#reset").click(function() {  
  4.         $("#form").reset();  
  5.     });  
  6. });  

這些代碼選擇ID為"form"的元素并對(duì)每個(gè)選擇的元素調(diào)用reset()。當(dāng)你有多于一個(gè)form時(shí),你也可以這樣做:
代碼
  1. $(document).ready(function() {  
  2.     // use this to reset several forms at once  
  3.     $("#reset").click(function() {  
  4.         $("form").reset();  
  5.     });  
  6. });  

這將在你的document里選擇所有的forms,迭代它們并對(duì)每個(gè)調(diào)用reset()。
另一個(gè)你可能面臨的問(wèn)題是不選擇某一個(gè)元素。jQuery為它提供filter()和not()。filter()通過(guò)滿足該filter表達(dá)式來(lái)減少選擇的元素,not()則相反刪除掉
所有滿足該表達(dá)式的元素。考慮一個(gè)unordered的list,你想選擇所有沒(méi)有ul子元素的li元素。
代碼
  1. $(document).ready(function() {  
  2.     $("li").not("[ul]").css("border", "1px solid black");  
  3. });  

這將選擇所有的li元素并刪除有ul子元素的元素。因此所有的li元素將有一個(gè)border,除了有ul子元素的。[expression]語(yǔ)法來(lái)自XPath并且可以用來(lái)被子元素
和屬性filter。可能你想選擇所有的有一個(gè)name屬性的anchors:
代碼
  1. $(document).ready(function() {  
  2.     $("a[@name]").background("#eee");  
  3. });  

這將對(duì)所有的有一個(gè)name屬性的anchor元素添加一個(gè)background顏色。
比通過(guò)name選擇anchors更常用的是,你可能需要通過(guò)它們的"href"屬性選擇anchors。由于瀏覽器的行為不一致這可能返回不同的"href"值(注意:這個(gè)問(wèn)題最近
在jQuery中解決了,只要在1.1.1版本后都可以)。為了只匹配一部分值,我們可以使用包含選擇"*="來(lái)代替等于"=":
代碼
  1. $(document).ready(function() {  
  2.     $("a[@href*=/content/gallery]").click(function() {  
  3.         // do something with all links that point somewhere to /content/gallery  
  4.     });  
  5. });  

到目前為止,所有的selectors用來(lái)選擇子或filter當(dāng)前選擇。還有你需要選擇前一個(gè)或下一個(gè)元素的情況,即所謂的siblings。考慮FAQ頁(yè)面,所有的答案首先
隱藏,而當(dāng)問(wèn)題點(diǎn)擊時(shí)顯示。該jQuery代碼為:
代碼
  1. $(document).ready(function() {  
  2.     $('#faq').find('dd').hide().end().find('dt').click(function() {  
  3.         $(this).next().slideToggle();  
  4.     });  
  5. });  

這里我們使用鏈來(lái)減少代碼量并得到更好的性能,因?yàn)?#faq'只選擇了一次。
通過(guò)使用end(),第一個(gè)find()不會(huì)結(jié)束,則我們可以對(duì)#faq元素繼續(xù)搜索下一個(gè)find(),而不是對(duì)dd子元素操作。
在click處理器即傳遞給click()方法的function里,我們使用$(this).next()來(lái)從當(dāng)前dt查找下一個(gè)sibling。這允許我們快速選擇緊跟在點(diǎn)擊的問(wèn)題后的答案。
除了sibling,你也可以選擇父元素(對(duì)屬性XPath的人而言為所謂的ancestors)。你可能想對(duì)用戶hover的鏈接的父paragraph高亮,試試這個(gè):
代碼
  1. $(document).ready(function() {  
  2.     $("a").hover(function() {  
  3.         $(this).parents("p").addClass("highlight");  
  4.     },function() {  
  5.         $(this).parents("p").removeClass("highlight");  
  6.     });  
  7. });  

對(duì)于所有hover的anchor元素,搜索它的父paragraph并添加和刪除一個(gè)"highlight" class。
讓我們繼續(xù)之前了解一下:jQuery很多時(shí)候是讓代碼變得更短而更容易閱讀和維護(hù)。以下是一個(gè)$(document).ready(callback)記號(hào)的捷徑:
代碼
  1. $(function() {  
  2.     // code to execute when the DOM is ready  
  3. });  

對(duì)于Hello world!例子,我們可以這樣寫:
代碼
  1. $(function() {  
  2.     $("a").click(function() {  
  3.         alert("Hello world!");  
  4.     });  
  5. });  

現(xiàn)在有了基本知識(shí)后,我們想explore一些其它方面,開(kāi)始使用AJAX。
本節(jié)里有意思的鏈接:
jQuery API documentation
Visual jQuery - A catgorized browsable API documentation.
jQuery Selectors
jQuery Events
jQuery DOM Traversing

Rate me: 使用Ajax
在這個(gè)部分我們寫一個(gè)小Ajax程序,它允許用戶rate something,就像在youtube.com上做的一樣。
我們需要一些服務(wù)器端代碼來(lái)完成這個(gè)。我的例子使用php文件來(lái)讀"rating"參數(shù)并返回ratings的數(shù)量和平均的rating。看看rate.php的服務(wù)器端代碼。
我們想讓這個(gè)例子用Ajax來(lái)工作,因此我們用jQuery生成一些必要的東西并加到一個(gè)ID為"rating"的容器里

代碼
  1. $(document).ready(function() {  
  2.     // generate markup  
  3.     $("#rating").append("Please rate: ");  
  4.   
  5.     for ( var i = 1; i <=5; i++ )  
  6.         $("#rating").append("<a href='#'>" + i + "</a>");  
  7.   
  8.     // add markup to container and applier click handlers to anchors  
  9.     $("$raing a ").click(function(e)   
  10.         // send request  
  11.         $.post("rate.php", {rating: $(this).html()}, function(xml) {  
  12.             // format and output result  
  13.             $("#rating").html(  
  14.                 "Thanks for rating, current average: " +   
  15.                 $("average", xml).text() +  
  16.                 ", number of votes: " +  
  17.                 $("count", xml).text()  
  18.             );  
  19.         });  
  20.   
  21.         // stop normal link click  
  22.         return false;  
  23.     });  
  24. });  

這個(gè)代碼片段生成5個(gè)anchor元素并把它們添加到id為"rating"的容器元素。最后,對(duì)容器里的每個(gè)anchor添加一個(gè)click處理器。當(dāng)點(diǎn)擊anchor時(shí),一個(gè)以anchor
的內(nèi)容為參數(shù)的post請(qǐng)求發(fā)送到rate.php。結(jié)果作為一個(gè)XML返回,并添加到容器代替anchors。
如果你手頭上沒(méi)有一個(gè)安裝的PHP服務(wù)器,你可以看看一個(gè)online example。對(duì)于一個(gè)非常好的甚至不用JavaScript工作的rating系統(tǒng)的例子,訪問(wèn)softonic.de
點(diǎn)擊"Kurz bewerten!"
jQuery的Ajax方法的更多的文檔可以在Ajax Documentation或者用Ajax開(kāi)發(fā)的Visual jQuery上找到。
當(dāng)通過(guò)Ajax載入內(nèi)容時(shí)遇到的一個(gè)非常常見(jiàn)的問(wèn)題是:當(dāng)添加事件處理器到你的文檔時(shí),如果事件處理器也適合載入的內(nèi)容,則你必須在內(nèi)容載入之后也添加這些
處理器。為了防止代碼重復(fù),你可以寫一個(gè)方法代理。例如:
代碼
  1. function addClickHandlers() {  
  2.     $("a.remote", this).click(function() {  
  3.         $("#target").load(this.href, addClickHandlers);  
  4.     });  
  5. }  
  6. $(document).ready(addClickHandlers);  

現(xiàn)在一旦當(dāng)DOM為ready以及每次當(dāng)一個(gè)用戶點(diǎn)擊class為remote的鏈接并且內(nèi)容完成載入后addClickHandlers都會(huì)被調(diào)用。
注意$("a.remote", this)查詢,this傳遞過(guò)來(lái)作為一個(gè)context:對(duì)于document ready事件,this表示document,則它搜索整個(gè)document中class為remote的anchors
當(dāng)addClickHandlers用來(lái)作為load()的回調(diào)時(shí),this表示另一個(gè)不同的元素:在這個(gè)例子中,表示id為target的元素。這防止了click事件一次又一次的賦給同一
鏈接,從而最終導(dǎo)致崩潰。
回調(diào)的另一個(gè)常見(jiàn)的問(wèn)題是參數(shù)。你已經(jīng)指定了你的回調(diào)但是需要傳遞一個(gè)額外的參數(shù)。達(dá)到次目標(biāo)的最簡(jiǎn)單的方式是在另一個(gè)方法里包裝回調(diào):
代碼
  1. // get some data  
  2. var foobar = ...;  
  3.   
  4. // specify handler, it needs data as a parameter  
  5. function handler(data) {  
  6.     // ...  
  7. }  
  8.   
  9. // add click handler and pass foobar!  
  10. $('a').click(function() {  
  11.     handler(foobar);  
  12. });  
  13.   
  14. // if you need the context of the original handler, use apply:  
  15. $('a').click(function() {  
  16.     handler.apply(this, [foobar]);  
  17. });  

使用Ajax我們可以cover許多"Web 2.0"。既然我們已經(jīng)看了一些基本的Ajax,讓我們添加一些簡(jiǎn)單的effects和animations到頁(yè)面中。
本節(jié)有意思的鏈接:
jQuery Ajax Documentation
jQuery API - 包含所有的jQuery方法的描述和例子
Thick Box - 一個(gè)使用jQuery來(lái)加強(qiáng)著名的lightbox的jQuery插件

Animate me: 使用Effects
可以使用jQuery的show()和hide()構(gòu)建的簡(jiǎn)單的animations。

代碼
  1. $(document).ready(function() {  
  2.     $("a").toggle(function() {  
  3.         $(".stuff").hide('slow');  
  4.     },function() {  
  5.         $(".stuff").show('fast');  
  6.     });  
  7. });  

你可以使用animate()創(chuàng)建任何animations的聯(lián)合。例如,一個(gè)具有fade的slide:
代碼
  1. $(document).ready(function() {  
  2.     $("a").toggle(function() {  
  3.         $(".stuff").animate({ height: 'hide', opacity: 'hide' }, 'slow');  
  4.     },function() {  
  5.         $(".stuff").animate({ height: 'show', opacity: 'show' }, 'slow');  
  6.     });  
  7. });  

更炫的effects可以在interface plugin collection找到。該站點(diǎn)提供demos和文檔。雖然Interface在jQuery的插件列表的最前面,還有許多其他的插件。下一
部分顯示了怎樣使用tablesorter插件。
本節(jié)有意思的鏈接:
jQuery Effects Documentation
Interface plugin

Sort me: 使用tablesorter plugin
tablesorter插件允許在客戶端對(duì)表格排序。你只需引入jQuery和插件,并告訴插件哪個(gè)表格是你想排序的。
添加以下內(nèi)容到starterkit.html(下jquery引入的下面)來(lái)嘗試該例子:

代碼
  1. <script src="lib/jquery.tablesorterjs"></script>  

引入了該插件后,你可以像這樣調(diào)用它:
代碼
  1. $(document).ready(function() {  
  2.     $("#large").tableSorter();  
  3. });  

試著點(diǎn)擊table的頭部并看看它怎樣在第一次升序排序以及第二次降序排序。該表格可以使用一些行高亮,我們可以通過(guò)傳遞一些選項(xiàng)來(lái)添加這個(gè):
代碼
  1. $(document).ready(function() {  
  2.     $("#large").tableSorter({  
  3.         // Class names for striping supplied as a array.  
  4.         stripingRowClass: ['odd', 'even'],  
  5.         // Stripe rows on tableSorter init  
  6.         stripeRowsOnStartUp: true  
  7.     });  
  8. });  

tablesorter homepage有更多關(guān)于可得到的選項(xiàng)的例子和文檔。
大多數(shù)插件可以像這樣使用:引入插件文件并在某些元素上調(diào)用插件方法,傳遞一些選項(xiàng)設(shè)置來(lái)定制插件。
一個(gè)可得到的up-to-date插件列表可以在jQuery Plugin site找到。
當(dāng)你使用jQuery的越頻繁,你可能發(fā)現(xiàn)把你自己的代碼打包成一個(gè)插件非常有用,可以為你自己或者你的公司重用它,或者與社區(qū)分享。下一節(jié)講述了怎樣構(gòu)建
一個(gè)插件。
本節(jié)有意思的鏈接:
Plugins for jQuery
Tablesorter Plugin

Plug me: 寫你自己的plugins
為jQuery寫你自己的插件非常簡(jiǎn)單。如果你遵循下面的規(guī)則,則其他人集成你的插件也非常簡(jiǎn)單。
插件命名
為你的插件找一個(gè)名字,讓我們稱我們的例子為"foobar"。創(chuàng)建一個(gè)名為jquery.[yourpluginname].js文件,例如,jquery.foobar.js。
添加一個(gè)自定義方法
通過(guò)擴(kuò)展jQuery對(duì)象來(lái)創(chuàng)建一個(gè)或多個(gè)插件方法,例如:

代碼
  1. jQuery.fn.foobar = function() {  
  2.     // do something  
  3. };  

則通過(guò)執(zhí)行下面代碼就可以得到使用上面的插件:
代碼
  1. $(...).foobar();  

默認(rèn)設(shè)置:
創(chuàng)建可以被用戶更改的默認(rèn)設(shè)置,例如:
代碼
  1. jQuery.fn.foobar = function(options) {  
  2.     var settings = jQuery.extend({  
  3.         value: 5, name: "pete", bar: 655  
  4.     }, options);  
  5. };  

你可以調(diào)用該插件而不帶選項(xiàng),即使用默認(rèn)配置:
代碼
  1. $("...").foobar();  

或者帶一些選項(xiàng):
代碼
  1. $("...").foobar({ value: 123, bar: 9 });  

文檔
如果你發(fā)表你的插件,你應(yīng)該也提供一些例子和文檔。有許多插件可以作為很好的參考。
現(xiàn)在你應(yīng)該具有了寫插件的基本知識(shí)。讓我們來(lái)寫一個(gè)我們自己的插件。
Checkbox插件
很多人使用jQuery來(lái)處理表單時(shí)會(huì)問(wèn)到radio buttons或checkboxes的checking和unchecking。他們常用這樣的代碼:
代碼
  1. $("input[@type='checkbox']").each(function() {  
  2.     this.checked = true;  
  3.     this.checked = false; // or, to uncheck  
  4.     this.checked = !this.checked; // or, to toggle  
  5. });  

無(wú)論何時(shí)你的代碼里有一個(gè)each時(shí),你可能想重寫它為一個(gè)插件,非常直接:
代碼
  1. jQuery.fn.check = function() {  
  2.     return this.each(function() {  
  3.         this.checked = true;  
  4.     });  
  5. };  

現(xiàn)在該插件可以使用了:
代碼
  1. $("input[@type='checkbox']").check();  

現(xiàn)在你也可以為uncheck()和toggleCheck()寫插件了。但是我們通過(guò)擴(kuò)展我們的插件來(lái)接收一些選項(xiàng)來(lái)替代。
代碼
  1. jQuery.fn.check = function(mode) {  
  2.     // if mode is undefined, use 'on' as default  
  3.     var mode = mode || 'on';  
  4.   
  5.     return this.each(function() {  
  6.         switch(mode) {  
  7.             case 'on':  
  8.                 this.checked = true;  
  9.                 break;  
  10.             case 'off':  
  11.                 this.checked = false;  
  12.                 break;  
  13.             case 'toggle':  
  14.                 this.checked = !this.checked;  
  15.                 break;  
  16.         }  
  17.     });  
  18. };  

我們可以提供選項(xiàng)"on","off"和"toggle"或者默認(rèn)無(wú)選項(xiàng),例如:
代碼
  1. $("input[@type='checkbox']").check();  
  2. $("input[@type='checkbox']").check('on');  
  3. $("input[@type='checkbox']").check('off');  
  4. $("input[@type='checkbox']").check('toggle');  

可選設(shè)置
寫多于一個(gè)設(shè)置選項(xiàng)會(huì)變得復(fù)雜,因?yàn)槿绻脩粝胧÷缘谝粋€(gè)參數(shù)而只使用第二個(gè)參數(shù)時(shí)他必須傳遞一個(gè)null值。
上一節(jié)中對(duì)tablesorter的使用證明了使用一個(gè)對(duì)象來(lái)解決這個(gè)問(wèn)題。用戶可以省略所有的參數(shù)或者為每個(gè)他想override的設(shè)置傳遞一個(gè)具有鍵/值對(duì)的對(duì)象。
出于練習(xí),你可以嘗試重寫第4節(jié)的Voting代碼為一個(gè)插件。插件骨架可能看起來(lái)像這樣:
代碼
  1. jQuery.fn.rateMe = function(options) {  
  2.     // instead of slecting a static container with  
  3.     // $("#rating"), we now use the jQuery context  
  4.     var container = this;  
  5.   
  6.     var settings = jQuery.extend({  
  7.         url: "rate.php"  
  8.         // put more defaults here  
  9.     }, options);  
  10.   
  11.     // ... rest of the code ...  
  12.   
  13.     // if possible, return "this" to not break the chain  
  14.     return this;  
  15. });  

則可以允許你像這樣允許該插件:
代碼
  1. $(...).rateMe({ url: "test.php" });  

Next steps
如果你計(jì)劃開(kāi)發(fā)更多的JavaScript,你應(yīng)該考慮稱為FireBug的Firefox插件。它提供一個(gè)console(很好的替代alerts),一個(gè)debugger和其他有用的stuff來(lái)為
JavaScript開(kāi)發(fā)。
如果你有不能解決的問(wèn)題、想分享的主意或者只是需要用jQuery表達(dá)你的看法,請(qǐng)自由舒暢的post給jQuery mailing list
對(duì)于與本指南相關(guān)的任何東西請(qǐng)?jiān)谖业?a target="blank">blog上post一個(gè)comment或者直接聯(lián)系我。
Whats left...Thanks a lot to John Resig for this greate library! Thanks to the jQuery community for providing John with enough coffee
and everything else!