Added in some changes to class handling and some docs for jQuery.nth().
[jquery.git] / src / jquery / jquery.js
index af72969..2ce32e1 100644 (file)
@@ -162,6 +162,8 @@ var $ = jQuery;
  * technically, chainable - there really isn't much use for chaining against it.
  * You can have as many $(document).ready events on your page as you like.
  *
+ * See ready(Function) for details about the ready event. 
+ * 
  * @example $(function(){
  *   // Document is ready
  * });
@@ -485,7 +487,27 @@ jQuery.fn = jQuery.prototype = {
         * @type String
         * @cat DOM
         */
+
+       /**
+        * Set the text contents of all matched elements. This has the same
+        * effect as calling .html() with your specified string.
+        *
+        * @example $("p").text("Some new text.");
+        * @before <p>Test Paragraph.</p>
+        * @result <p>Some new text.</p>
+        *
+        * @param String val The text value to set the contents of the element to.
+        *
+        * @name text
+        * @type String
+        * @cat DOM
+        */
        text: function(e) {
+               // A surprisingly high number of people expect the
+               // .text() method to do this, so lets do it!
+               if ( typeof e == "string" )
+                       return this.html( e );
+
                e = e || this;
                var t = "";
                for ( var j = 0; j < e.length; j++ ) {
@@ -1213,28 +1235,21 @@ jQuery.extend({
        },
 
        className: {
-               add: function(o,c){
-                       if (jQuery.className.has(o,c)) return;
-                       o.className += ( o.className ? " " : "" ) + c;
+               add: function( elem, c ){
+                       if ( jQuery.className.has( elem, c ) )
+                return;
+                       elem.className += ( elem.className ? " " : "" ) + c;
                },
-               remove: function(o,c){
-                       if( !c ) {
-                               o.className = "";
-                       } else {
-                               var classes = o.className.split(" ");
-                               for(var i=0; i<classes.length; i++) {
-                                       if(classes[i] == c) {
-                                               classes.splice(i, 1);
-                                               break;
-                                       }
-                               }
-                               o.className = classes.join(' ');
-                       }
+               remove: function( elem, c ){
+            elem.className = c ?
+                jQuery.grep( elem.className.split(/\s+/), function(cur){ 
+                                   return jQuery.className.has( c, cur );      
+                }).join(' ') : "";
                },
-               has: function(e,a) {
-                       if ( e.className != undefined )
-                               e = e.className;
-                       return new RegExp("(^|\\s)" + a + "(\\s|$)").test(e);
+               has: function( elem, c ){
+                       if ( elem.className != undefined )
+                               elem = elem.className;
+                       return new RegExp("(^|\\s)" + c + "(\\s|$)").test( elem );
                }
        },
 
@@ -1385,6 +1400,18 @@ jQuery.extend({
                return r;
        },
 
+       /**
+        * A handy, and fast, way to traverse in a particular direction and find
+        * a specific element.
+        *
+        * @private
+        * @name $.nth
+        * @type DOMElement
+        * @param DOMElement cur The element to search from.
+        * @param Number|String num The Nth result to match. Can be a number or a string (like 'even' or 'odd').
+        * @param String dir The direction to move in (pass in something like 'previousSibling' or 'nextSibling').
+        * @cat DOM/Traversing
+        */
        nth: function(cur,result,dir){
                result = result || 1;
                var num = 0;
@@ -1441,7 +1468,7 @@ jQuery.extend({
                        submit: "a.type=='submit'",
                        image: "a.type=='image'",
                        reset: "a.type=='reset'",
-                       button: "a.type=='button'",
+                       button: "a.type=='button'||a.nodeName=='BUTTON'",
                        input: "/input|select|textarea|button/i.test(a.nodeName)"
                },
                ".": "jQuery.className.has(a,m[2])",
@@ -1451,20 +1478,24 @@ jQuery.extend({
                        "^=": "z && !z.indexOf(m[4])",
                        "$=": "z && z.substr(z.length - m[4].length,m[4].length)==m[4]",
                        "*=": "z && z.indexOf(m[4])>=0",
-                       "": "z"
+                       "": "z",
+                       _resort: function(m){
+                               return ["", m[1], m[3], m[2], m[5]];
+                       },
+                       _prefix: "z=jQuery.attr(a,m[3]);"
                },
                "[": "jQuery.find(m[2],a).length"
        },
 
-  /**
+       /**
         * All elements on a specified axis.
         *
         * @private
         * @name $.sibling
         * @type Array
         * @param Element elem The element to find all the siblings of (including itself).
-   * @cat DOM/Traversing
-   */
+        * @cat DOM/Traversing
+        */
        sibling: function( n, elem ) {
                var r = [];
 
@@ -1709,7 +1740,8 @@ jQuery.extend({
                        value: "value",
                        disabled: "disabled",
                        checked: "checked",
-                       readonly: "readOnly"
+                       readonly: "readOnly",
+                       selected: "selected"
                };
                
                // IE actually uses filters for opacity ... elem is actually elem.style
@@ -1757,7 +1789,7 @@ jQuery.extend({
                "\\[ *(@)S *([!*$^=]*) *('?\"?)(.*?)\\4 *\\]",
 
                // Match: [div], [div p]
-               "(\\[)\s*(.*?)\s*\\]",
+               "(\\[)\\s*(.*?)\\s*\\]",
 
                // Match: :contains('foo')
                "(:)S\\(\"?'?([^\\)]*?)\"?'?\\)",
@@ -1783,8 +1815,8 @@ jQuery.extend({
 
                                if ( m ) {
                                        // Re-organize the first match
-                                       if ( !i )
-                                               m = ["",m[1], m[3], m[2], m[5]];
+                                       if ( jQuery.expr[ m[1] ]._resort )
+                                               m = jQuery.expr[ m[1] ]._resort( m );
 
                                        // Remove what we just matched
                                        t = t.replace( re, "" );
@@ -1815,7 +1847,7 @@ jQuery.extend({
 
                                // Build a custom macro to enclose it
                                eval("f = function(a,i){" +
-                                       ( m[1] == "@" ? "z=jQuery.attr(a,m[3]);" : "" ) +
+                                       ( jQuery.expr[ m[1] ]._prefix || "" ) +
                                        "return " + f + "}");
 
                                // Execute it against the current filter
@@ -2018,12 +2050,16 @@ jQuery.extend({
 
                // Bind an event to an element
                // Original by Dean Edwards
-               add: function(element, type, handler) {
+               add: function(element, type, handler, data) {
                        // For whatever reason, IE has trouble passing the window object
                        // around, causing it to be cloned in the process
                        if ( jQuery.browser.msie && element.setInterval != undefined )
                                element = window;
 
+                       // if data is passed, bind to handler
+                       if( data ) 
+                               handler.data = data;
+
                        // Make sure that the function being executed has a unique ID
                        if ( !handler.guid )
                                handler.guid = this.guid++;
@@ -2063,7 +2099,9 @@ jQuery.extend({
                // Detach an event or set of events from an element
                remove: function(element, type, handler) {
                        if (element.events)
-                               if (type && element.events[type])
+                               if ( type && type.type )
+                                       delete element.events[ type.type ][ type.handler.guid ];
+                               else if (type && element.events[type])
                                        if ( handler )
                                                delete element.events[type][handler.guid];
                                        else
@@ -2100,9 +2138,6 @@ jQuery.extend({
 
                        event = jQuery.event.fix( event || window.event || {} ); // Empty object is for triggered events with no data
 
-                       // If no correct event was found, fail
-                       if ( !event ) return false;
-
                        var returnValue = true;
 
                        var c = this.events[event.type];
@@ -2111,6 +2146,11 @@ jQuery.extend({
                        args.unshift( event );
 
                        for ( var j in c ) {
+                               // Pass in a reference to the handler function itself
+                               // So that we can later remove it
+                               args[0].handler = c[j];
+                               args[0].data = c[j].data;
+
                                if ( c[j].apply( this, args ) === false ) {
                                        event.preventDefault();
                                        event.stopPropagation();
@@ -2119,26 +2159,25 @@ jQuery.extend({
                        }
 
                        // Clean up added properties in IE to prevent memory leak
-                       if (jQuery.browser.msie) event.target = event.preventDefault = event.stopPropagation = null;
+                       if (jQuery.browser.msie) event.target = event.preventDefault = event.stopPropagation = event.handler = event.data = null;
 
                        return returnValue;
                },
 
                fix: function(event) {
-                       // check IE
-                       if(jQuery.browser.msie) {
-                               // fix target property, if available
-                               // check prevents overwriting of fake target coming from trigger
-                               if(event.srcElement)
-                                       event.target = event.srcElement;
-                                       
-                               // calculate pageX/Y
+                       // Fix target property, if necessary
+                       if ( !event.target && event.srcElement )
+                               event.target = event.srcElement;
+
+                       // Calculate pageX/Y if missing and clientX/Y available
+                       if ( typeof event.pageX == "undefined" && typeof event.clientX != "undefined" ) {
                                var e = document.documentElement, b = document.body;
                                event.pageX = event.clientX + (e.scrollLeft || b.scrollLeft);
                                event.pageY = event.clientY + (e.scrollTop || b.scrollTop);
+                       }
                                        
-                       // check safari and if target is a textnode
-                       } else if(jQuery.browser.safari && event.target.nodeType == 3) {
+                       // Check safari and if target is a textnode
+                       if ( jQuery.browser.safari && event.target.nodeType == 3 ) {
                                // target is readonly, clone the event object
                                event = jQuery.extend({}, event);
                                // get parentnode from textnode
@@ -2146,15 +2185,17 @@ jQuery.extend({
                        }
                        
                        // fix preventDefault and stopPropagation
-                       if (!event.preventDefault)
+                       if (!event.preventDefault) {
                                event.preventDefault = function() {
                                        this.returnValue = false;
                                };
+                       }
                                
-                       if (!event.stopPropagation)
+                       if (!event.stopPropagation) {
                                event.stopPropagation = function() {
                                        this.cancelBubble = true;
                                };
+                       }
                                
                        return event;
                }
@@ -2602,6 +2643,7 @@ jQuery.macros = {
 
                /**
                 * Get the html contents of the first matched element.
+                * This property is not available on XML documents.
                 *
                 * @example $("div").html();
                 * @before <div><input/></div>
@@ -2614,6 +2656,7 @@ jQuery.macros = {
 
                /**
                 * Set the html contents of every matched element.
+                * This property is not available on XML documents.
                 *
                 * @example $("div").html("<b>new stuff</b>");
                 * @before <div><input/></div>
@@ -2816,35 +2859,7 @@ jQuery.macros = {
                 * Get a set of elements containing the unique ancestors of the matched
                 * set of elements (except for the root element).
                 *
-                * @example $("span").ancestors()
-                * @before <html><body><div><p><span>Hello</span></p><span>Hello Again</span></div></body></html>
-                * @result [ <body>...</body>, <div>...</div>, <p><span>Hello</span></p> ]
-                *
-                * @name ancestors
-                * @type jQuery
-                * @cat DOM/Traversing
-                */
-
-               /**
-                * Get a set of elements containing the unique ancestors of the matched
-                * set of elements, and filtered by an expression.
-                *
-                * @example $("span").ancestors("p")
-                * @before <html><body><div><p><span>Hello</span></p><span>Hello Again</span></div></body></html>
-                * @result [ <p><span>Hello</span></p> ]
-                *
-                * @name ancestors
-                * @type jQuery
-                * @param String expr An expression to filter the ancestors with
-                * @cat DOM/Traversing
-                */
-               ancestors: jQuery.parents,
-
-               /**
-                * Get a set of elements containing the unique ancestors of the matched
-                * set of elements (except for the root element).
-                *
-                * @example $("span").ancestors()
+                * @example $("span").parents()
                 * @before <html><body><div><p><span>Hello</span></p><span>Hello Again</span></div></body></html>
                 * @result [ <body>...</body>, <div>...</div>, <p><span>Hello</span></p> ]
                 *
@@ -2857,7 +2872,7 @@ jQuery.macros = {
                 * Get a set of elements containing the unique ancestors of the matched
                 * set of elements, and filtered by an expression.
                 *
-                * @example $("span").ancestors("p")
+                * @example $("span").parents("p")
                 * @before <html><body><div><p><span>Hello</span></p><span>Hello Again</span></div></body></html>
                 * @result [ <p><span>Hello</span></p> ]
                 *
@@ -3169,12 +3184,24 @@ jQuery.macros = {
                 * default behaviour. To stop both default action and event bubbling, your handler
                 * has to return false.
                 *
+                * In most cases, you can define your event handlers as anonymous functions
+                * (see first example). In cases where that is not possible, you can pass additional
+                * data as the second paramter (and the handler function as the third), see 
+                * second example.
+                *
                 * @example $("p").bind( "click", function() {
                 *   alert( $(this).text() );
                 * } )
                 * @before <p>Hello</p>
                 * @result alert("Hello")
                 *
+                * @example var handler = function(event) {
+                *   alert(event.data.foo);
+                * };
+                * $("p").bind( "click", {foo: "bar"}, handler)
+                * @result alert("bar")
+                * @desc Pass some additional data to the event handler.
+                *
                 * @example $("form").bind( "submit", function() { return false; } )
                 * @desc Cancel a default action and prevent it from bubbling by returning false
                 * from your function.
@@ -3193,11 +3220,12 @@ jQuery.macros = {
                 * @name bind
                 * @type jQuery
                 * @param String type An event type
+                * @param Object data (optional) Additional data passed to the event handler as event.data
                 * @param Function fn A function to bind to the event on each of the set of matched elements
                 * @cat Events
                 */
-               bind: function( type, fn ) {
-                       jQuery.event.add( this, type, fn );
+               bind: function( type, data, fn ) {
+                       jQuery.event.add( this, type, fn || data, data );
                },
 
                /**
@@ -3263,4 +3291,4 @@ jQuery.macros = {
        }
 };
 
-jQuery.init();
+jQuery.init();
\ No newline at end of file