Massive update, bugs, filesize, new features - getting ready for 1.0.
[jquery.git] / jquery / jquery.js
1 /*
2  * jQuery (jquery.com)
3  *
4  * Copyright (c) 2006 John Resig (ejohn.org)
5  * Licensed under the MIT License:
6  *   http://www.opensource.org/licenses/mit-license.php
7  *
8  * $Date$
9  * $Rev$
10  */
11
12 // Global undefined variable
13 window.undefined = window.undefined;
14
15 function jQuery(a,c) {
16         this.cur = $.Select(
17                 a || $.context || document,
18                 c && c.$jquery && c.get(0) || c
19         );
20 }
21
22 if ( window.$ == undefined )
23         var $ = function(a,c) {
24                 return new jQuery(a,c);
25         };
26
27 jQuery.prototype = $.fn = {
28         $jquery: "$Rev$",
29         
30         // The only two getters
31         size: function() {
32                 return this.get().length;
33         },
34         get: function(i) {
35                 return i == undefined ? this.cur : this.cur[i];
36         },
37         
38         each: function(f) {
39                 for ( var i = 0; i < this.size(); i++ )
40                         f.apply( this.get(i), [i] );
41                 return this;
42         },
43         set: function(a,b) {
44                 return this.each(function(){
45                         if ( b == undefined )
46                                 for ( var j in a )
47                                         $.attr(this,j,a[j]);
48                         else
49                                 $.attr(this,a,b);
50                 });
51         },
52         html: function(h) {
53                 return h == undefined && this.size() ?
54                         this.get(0).innerHTML : this.set( "innerHTML", h );
55         },
56         val: function(h) {
57                 return h == undefined && this.size() ?
58                         this.get(0).value : this.set( "value", h );
59         },
60         text: function(e) {
61                 e = e || this.get();
62                 var t = "";
63                 for ( var j = 0; j < e.length; j++ )
64                         for ( var i = 0; i < e[j].childNodes.length; i++ )
65                                 t += e[j].childNodes[i].nodeType != 1 ?
66                                         e[j].childNodes[i].nodeValue :
67                                         $.fn.text(e[j].childNodes[i].childNodes);
68                 return t;
69         },
70         
71         css: function(a,b) {
72                 return  a.constructor != String || b ?
73                         this.each(function(){
74                                 if ( !b )
75                                         for ( var j in a )
76                                                 $.attr(this.style,j,a[j]);
77                                 else
78                                         $.attr(this.style,a,b);
79                         }) : $.css( this.get(0), a );
80         },
81         toggle: function() {
82                 return this.each(function(){
83                         var d = $.css(this,"display");
84                         if ( d == "none" || d === "" )
85                                 $(this).show();
86                         else
87                                 $(this).hide();
88                 });
89         },
90         show: function() {
91                 return this.each(function(){
92                         this.style.display = this.oldblock ? this.oldblock : "";
93                         if ( $.css(this,"display") == "none" )
94                                 this.style.display = "block";
95                 });
96         },
97         hide: function() {
98                 return this.each(function(){
99                         this.oldblock = $.css(this,"display");
100                         if ( this.oldblock == "none" )
101                                 this.oldblock = "block";
102                         this.style.display = "none";
103                 });
104         },
105         addClass: function(c) {
106                 return this.each(function(){
107                         $.class.add(this,c);
108                 });
109         },
110         removeClass: function(c) {
111                 return this.each(function(){
112                         $.class.remove(this,c);
113                 });
114         },
115         // TODO: Optomize
116         toggleClass: function(c) {
117                 return this.each(function(){
118                         if ($.hasWord(this,c))
119                                 $.class.remove(this,c);
120                         else
121                                 $.class.add(this,c);
122                 });
123         },
124         remove: function() {
125                 this.each(function(){this.parentNode.removeChild( this );});
126                 this.cur = [];
127                 return this;
128         },
129         
130         wrap: function() {
131                 var a = $.clean(arguments);
132                 return this.each(function(){
133                         var b = a[0].cloneNode(true);
134                         this.parentNode.insertBefore( b, this );
135                         while ( b.firstChild )
136                                 b = b.firstChild;
137                         b.appendChild( this );
138                 });
139         },
140         
141         append: function() {
142                 var clone = this.size() > 1;
143                 var a = $.clean(arguments);
144                 return this.domManip(function(){
145                         for ( var i = 0; i < a.length; i++ )
146                                 this.appendChild( clone ? a[i].cloneNode(true) : a[i] );
147                 });
148         },
149         
150         appendTo: function() {
151                 var a = arguments;
152                 return this.each(function(){
153                         for ( var i = 0; i < a.length; i++ )
154                                 $(a[i]).append( this );
155                 });
156         },
157         
158         prepend: function() {
159                 var clone = this.size() > 1;
160                 var a = $.clean(arguments);
161                 return this.domManip(function(){
162                         for ( var i = a.length - 1; i >= 0; i-- )
163                                 this.insertBefore( clone ? a[i].cloneNode(true) : a[i], this.firstChild );
164                 });
165         },
166         
167         before: function() {
168                 var clone = this.size() > 1;
169                 var a = $.clean(arguments);
170                 return this.each(function(){
171                         for ( var i = 0; i < a.length; i++ )
172                                 this.parentNode.insertBefore( clone ? a[i].cloneNode(true) : a[i], this );
173                 });
174         },
175         
176         after: function() {
177                 var clone = this.size() > 1;
178                 var a = $.clean(arguments);
179                 return this.each(function(){
180                         for ( var i = a.length - 1; i >= 0; i-- )
181                                 this.parentNode.insertBefore( clone ? a[i].cloneNode(true) : a[i], this.nextSibling );
182                 });
183         },
184         
185         empty: function() {
186                 return this.each(function(){
187                         while ( this.firstChild )
188                                 this.removeChild( this.firstChild );
189                 });
190         },
191         
192         bind: function(t,f) {
193                 return this.each(function(){$.event.add(this,t,f);});
194         },
195         unbind: function(t,f) {
196                 return this.each(function(){$.event.remove(this,t,f);});
197         },
198         trigger: function(t) {
199                 return this.each(function(){$.event.trigger(this,t);});
200         },
201         
202         find: function(t) {
203                 var old = [], ret = [];
204                 this.each(function(){
205                         old[old.length] = this;
206                         ret = $.merge( ret, $.Select(t,this) );
207                 });
208                 this.old = old;
209                 this.cur = ret;
210                 return this;
211         },
212         end: function() {
213                 this.cur = this.old;
214                 return this;
215         },
216         
217         parent: function(a) {
218                 this.cur = $.map(this.cur,"d.parentNode");
219                 if ( a ) this.cur = $.filter(a,this.cur).r;
220                 return this;
221         },
222         
223         parents: function(a) {
224                 this.cur = $.map(this.cur,$.parents);
225                 if ( a ) this.cur = $.filter(a,this.cur).r;
226                 return this;
227         },
228         
229         siblings: function(a) {
230                 // Incorrect, need to exclude current element
231                 this.cur = $.map(this.cur,$.sibling);
232                 if ( a ) this.cur = $.filter(a,this.cur).r;
233                 return this;
234         },
235         
236         filter: function(t) {
237                 this.cur = $.filter(t,this.cur).r;
238                 return this;
239         },
240         not: function(t) {
241                 this.cur = t.constructor == String ?
242                         $.filter(t,this.cur,false).r :
243                         $.grep(this.cur,function(a){ return a != t; });
244                 return this;
245         },
246         add: function(t) {
247                 this.cur = $.merge( this.cur, t.constructor == String ?
248                         $.Select(t) : t.constructor == Array ? t : [t] );
249                 return this;
250         },
251         is: function(t) {
252                 return $.filter(t,this.cur).r.length > 0;
253         },
254         
255         /**
256          * A wrapper function for each() to be used by append and prepend.
257          * Handles cases where you're trying to modify the inner contents of
258          * a table, when you actually need to work with the tbody.
259          */
260         domManip: function(fn){
261                 return this.each(function(){
262                         var obj = this;
263                         
264                         if ( this.nodeName == "TABLE" ) {
265                                 var tbody = this.getElementsByTagName("tbody");
266
267                                 if ( !tbody.length ) {
268                                         obj = document.createElement("tbody");
269                                         this.appendChild( obj );
270                                 } else
271                                         obj = tbody[0];
272                         }
273         
274                         fn.apply( obj );
275                 });
276         }
277 };
278
279 $.class = {
280         add: function(o,c){
281                 if ($.hasWord(o,c)) return;
282                 o.className += ( o.className.length > 0 ? " " : "" ) + c;
283         },
284         remove: function(o,c){
285                 o.className = !c ? "" :
286                         o.className.replace(
287                                 new RegExp("(^|\\s*\\b[^-])"+c+"($|\\b(?=[^-]))", "g"), "");
288         }
289 };
290
291 (function(){
292         var b = navigator.userAgent.toLowerCase();
293
294         // Figure out what browser is being used
295         $.browser =
296                 ( /webkit/.test(b) && "safari" ) ||
297                 ( /opera/.test(b) && "opera" ) ||
298                 ( /msie/.test(b) && "msie" ) ||
299                 ( !/compatible/.test(b) && "mozilla" ) ||
300                 "other";
301
302         // Check to see if the W3C box model is being used
303         $.boxModel = ( $.browser != "msie" || document.compatMode == "CSS1Compat" );
304 })();
305
306 $.css = function(e,p) {
307         // Adapted from Prototype 1.4.0
308         if ( p == "height" || p == "width" ) {
309
310                 // Handle extra width/height provided by the W3C box model
311                 var ph = (!$.boxModel ? 0 :
312                         $.css(e,"paddingTop") + $.css(e,"paddingBottom") +
313                         $.css(e,"borderTopWidth") + $.css(e,"borderBottomWidth")) || 0;
314
315                 var pw = (!$.boxModel ? 0 :
316                         $.css(e,"paddingLeft") + $.css(e,"paddingRight") +
317                         $.css(e,"borderLeftWidth") + $.css(e,"borderRightWidth")) || 0;
318
319                 var oHeight, oWidth;
320
321                 if ($.css(e,"display") != 'none') {
322                         oHeight = e.offsetHeight || parseInt(e.style.height) || 0;
323                         oWidth = e.offsetWidth || parseInt(e.style.width) || 0;
324                 } else {
325                         var els = e.style;
326                         var ov = els.visibility;
327                         var op = els.position;
328                         var od = els.display;
329                         els.visibility = "hidden";
330                         els.position = "absolute";
331                         els.display = "";
332                         oHeight = e.clientHeight || parseInt(e.style.height);
333                         oWidth = e.clientWidth || parseInt(e.style.width);
334                         els.display = od;
335                         els.position = op;
336                         els.visibility = ov;
337                 }
338
339                 return p == "height" ?
340                         (oHeight - ph < 0 ? 0 : oHeight - ph) :
341                         (oWidth - pw < 0 ? 0 : oWidth - pw);
342         }
343         
344         var r;
345
346         if (e.style[p])
347                 r = e.style[p];
348         else if (e.currentStyle)
349                 r = e.currentStyle[p];
350         else if (document.defaultView && document.defaultView.getComputedStyle) {
351                 p = p.replace(/([A-Z])/g,"-$1").toLowerCase();
352                 var s = document.defaultView.getComputedStyle(e,"");
353                 r = s ? s.getPropertyValue(p) : null;
354         }
355         
356         return /top|right|left|bottom/i.test(p) ? parseFloat( r ) : r;
357 };
358
359 $.clean = function(a) {
360         var r = [];
361         for ( var i = 0; i < a.length; i++ ) {
362                 if ( a[i].constructor == String ) {
363
364                         if ( !a[i].indexOf("<tr") ) {
365                                 var tr = true;
366                                 a[i] = "<table>" + a[i] + "</table>";
367                         } else if ( !a[i].indexOf("<td") || !a[i].indexOf("<th") ) {
368                                 var td = true;
369                                 a[i] = "<table><tbody><tr>" + a[i] + "</tr></tbody></table>";
370                         }
371
372                         var div = document.createElement("div");
373                         div.innerHTML = a[i];
374
375                         if ( tr || td ) {
376                                 div = div.firstChild.firstChild;
377                                 if ( td ) div = div.firstChild;
378                         }
379
380                         for ( var j = 0; j < div.childNodes.length; j++ )
381                                 r[r.length] = div.childNodes[j];
382                 } else if ( a[i].length && !a[i].nodeType )
383                         for ( var k = 0; k < a[i].length; k++ )
384                                 r[r.length] = a[i][k];
385                 else if ( a[i] !== null )
386                         r[r.length] =
387                                 a[i].nodeType ? a[i] : document.createTextNode(a[i].toString());
388         }
389         return r;
390 };
391
392 $.g = {
393         "": "m[2]== '*'||a.nodeName.toUpperCase()==m[2].toUpperCase()",
394         "#": "a.getAttribute('id')&&a.getAttribute('id')==m[2]",
395         ":": {
396                 lt: "i<m[3]-0",
397                 gt: "i>m[3]-0",
398                 nth: "m[3]-0==i",
399                 eq: "m[3]-0==i",
400                 first: "i==0",
401                 last: "i==r.length-1",
402                 even: "i%2==0",
403                 odd: "i%2==1",
404                 "first-child": "$.sibling(a,0).cur",
405                 "nth-child": "(m[3]=='even'?$.sibling(a,m[3]).n%2==0:(m[3]=='odd'?$.sibling(a,m[3]).n%2==1:$.sibling(a,m[3]).cur))",
406                 "last-child": "$.sibling(a,0,true).cur",
407                 "nth-last-child": "$.sibling(a,m[3],true).cur",
408                 "first-of-type": "$.ofType(a,0)",
409                 "nth-of-type": "$.ofType(a,m[3])",
410                 "last-of-type": "$.ofType(a,0,true)",
411                 "nth-last-of-type": "$.ofType(a,m[3],true)",
412                 "only-of-type": "$.ofType(a)==1",
413                 "only-child": "$.sibling(a).length==1",
414                 parent: "a.childNodes.length",
415                 empty: "!a.childNodes.length",
416                 root: "a==(a.ownerDocument||document).documentElement",
417                 contains: "(a.innerText||a.innerHTML).indexOf(m[3])!=-1",
418                 visible: "(!a.type||a.type!='hidden')&&($.css(a,'display')!= 'none'&&$.css(a,'visibility')!= 'hidden')",
419                 hidden: "(a.type&&a.type == 'hidden')||$.css(a,'display')=='none'||$.css(a,'visibility')== 'hidden'",
420                 enabled: "a.disabled==false",
421                 disabled: "a.disabled",
422                 checked: "a.checked"
423         },
424         ".": "$.hasWord(a,m[2])",
425         "@": {
426                 "=": "$.attr(a,m[3])==m[4]",
427                 "!=": "$.attr(a,m[3])!=m[4]",
428                 "~=": "$.hasWord($.attr(a,m[3]),m[4])",
429                 "|=": "!$.attr(a,m[3]).indexOf(m[4])",
430                 "^=": "!$.attr(a,m[3]).indexOf(m[4])",
431                 "$=": "$.attr(a,m[3]).substr( $.attr(a,m[3]).length - m[4].length,m[4].length )==m[4]",
432                 "*=": "$.attr(a,m[3]).indexOf(m[4])>=0",
433                 "": "m[3]=='*'?a.attributes.length>0:$.attr(a,m[3])"
434         },
435         "[": "$.Select(m[2],a).length"
436 };
437
438 $.token = [
439         "\\.\\.|/\\.\\.", "a.parentNode",
440         ">|/", "$.sibling(a.firstChild)",
441         "\\+", "$.sibling(a).next",
442         "~", function(a){
443                 var r = [];
444                 var s = $.sibling(a);
445                 if ( s.n > 0 )
446                         for ( var i = s.n; i < s.length; i++ )
447                                 r[r.length] = s[i];
448                 return r;
449         }
450 ];
451
452 $.Select = function( t, context ) {
453         context = context || $.context || document;
454         if ( t.constructor != String ) return [t];
455
456         if ( !t.indexOf("//") ) {
457                 context = context.documentElement;
458                 t = t.substr(2,t.length);
459         } else if ( !t.indexOf("/") ) {
460                 context = context.documentElement;
461                 t = t.substr(1,t.length);
462                 // FIX Assume the root element is right :(
463                 if ( t.indexOf("/") >= 1 )
464                         t = t.substr(t.indexOf("/"),t.length);
465         }
466
467         var ret = [context];
468         var done = [];
469         var last = null;
470
471         while ( t.length > 0 && last != t ) {
472     var r = [];
473                 last = t;
474
475     t = $.cleanSpaces(t).replace( /^\/\//i, "" );
476                 
477                 var foundToken = false;
478                 
479                 for ( var i = 0; i < $.token.length; i += 2 ) {
480                         var re = new RegExp("^(" + $.token[i] + ")");
481                         var m = re.exec(t);
482                         
483                         if ( m ) {
484                                 r = ret = $.map( ret, $.token[i+1] );
485                                 t = $.cleanSpaces( t.replace( re, "" ) );
486                                 foundToken = true;
487                         }
488                 }
489                 
490                 if ( !foundToken ) {
491
492                         if ( !t.indexOf(",") || !t.indexOf("|") ) {
493                                 if ( ret[0] == context ) ret.shift();
494                                 done = $.merge( done, ret );
495                                 r = ret = [context];
496                                 t = " " + t.substr(1,t.length);
497                         } else {
498                                 var re2 = /^([#.]?)([a-z0-9\\*_-]*)/i;
499                                 var m = re2.exec(t);
500         
501                                 if ( m[1] == "#" ) {
502                                         // Ummm, should make this work in all XML docs
503                                         var oid = document.getElementById(m[2]);
504                                         r = ret = oid ? [oid] : [];
505                                         t = t.replace( re2, "" );
506                                 } else {
507                                         if ( !m[2] || m[1] == "." ) m[2] = "*";
508         
509                                         for ( var i = 0; i < ret.length; i++ )
510                                                 r = $.merge( r, $.tag(ret[i],m[2]) );
511                                 }
512                         }
513                         
514                 }
515
516                 if ( t ) {
517                         var val = $.filter(t,r);
518                         ret = r = val.r;
519                         t = $.cleanSpaces(val.t);
520                 }
521         }
522
523         if ( ret && ret[0] == context ) ret.shift();
524         done = $.merge( done, ret );
525
526         return done;
527 };
528
529 $.tag = function(a,b){
530         return a && a.getElementsByTagName != undefined ?
531                 a.getElementsByTagName( b ) : [];
532 };
533
534 $.attr = function(o,a,v){
535         if ( a && a.constructor == String ) {
536                 var fix = {
537                         "for": "htmlFor",
538                         "class": "className",
539                         "float": "cssFloat"
540                 };
541                 a = (fix[a] && fix[a].replace && fix[a]) || a;
542                 var r = /-([a-z])/ig;
543                 a = a.replace(r,function(z,b){return b.toUpperCase();});
544                 if ( v != undefined ) {
545                         o[a] = v;
546                         if ( o.setAttribute && a != "disabled" )
547                                 o.setAttribute(a,v);
548                 }
549                 return o[a] || o.getAttribute(a) || "";
550         } else
551                 return "";
552 };
553
554 $.filter = function(t,r,not) {
555         var g = $.grep;
556         if ( not === false )
557                 g = function(a,f) {return $.grep(a,f,true);};
558
559         while ( t && t.match(/^[:\\.#\\[a-zA-Z\\*]/) ) {
560                 var re = /^\[ *@([a-z0-9*()_-]+) *([~!|*$^=]*) *'?"?([^'"]*)'?"? *\]/i;
561                 var m = re.exec(t);
562
563                 if ( m )
564                         m = ["", "@", m[2], m[1], m[3]];
565                 else {
566                         re = /^(\[) *([^\]]*) *\]/i;
567                         m = re.exec(t);
568
569                         if ( !m ) {
570                                 re = /^(:)([a-z0-9*_-]*)\( *["']?([^ \)'"]*)['"]? *\)/i;
571                                 m = re.exec(t);
572
573                                 if ( !m ) {
574                                         re = /^([:\.#]*)([a-z0-9*_-]*)/i;
575                                         m = re.exec(t);
576                                 }
577                         }
578                 }
579                 t = t.replace( re, "" );
580
581                 if ( m[1] == ":" && m[2] == "not" )
582                         r = $.filter(m[3],r,false).r;
583                 else {
584                         var f = null;
585
586                         if ( $.g[m[1]].constructor == String )
587                                 f = $.g[m[1]];
588                         else if ( $.g[m[1]][m[2]] )
589                                 f = $.g[m[1]][m[2]];
590
591                         if ( f ) {
592                                 eval("f = function(a,i){return " + f + "}");
593                                 r = g( r, f );
594                         }
595                 }
596         }
597
598         return { r: r, t: t };
599 };
600
601 $.parents = function(a){
602         var b = [];
603         var c = a.parentNode;
604         while ( c && c != document ) {
605                 b[b.length] = c;
606                 c = c.parentNode;
607         }
608         return b;
609 };
610
611 $.cleanSpaces = function(t){
612         return t.replace(/^\s+|\s+$/g, "");
613 };
614
615 $.ofType = function(a,n,e) {
616         var t = $.grep($.sibling(a),function(b){ return b.nodeName == a.nodeName; });
617         if ( e ) n = t.length - n - 1;
618         return n != undefined ? t[n] == a : t.length;
619 };
620
621 $.sibling = function(a,n,e) {
622         var type = [];
623         var tmp = a.parentNode.childNodes;
624         for ( var i = 0; i < tmp.length; i++ ) {
625                 if ( tmp[i].nodeType == 1 )
626                         type[type.length] = tmp[i];
627                 if ( tmp[i] == a )
628                         type.n = type.length - 1;
629         }
630         if ( e ) n = type.length - n - 1;
631         type.cur = ( type[n] == a );
632         type.prev = ( type.n > 0 ? type[type.n - 1] : null );
633         type.next = ( type.n < type.length - 1 ? type[type.n + 1] : null );
634         return type;
635 };
636
637 $.hasWord = function(e,a) {
638         if ( e == undefined ) return;
639         if ( e.className ) e = e.className;
640         return new RegExp("(^|\\s)" + a + "(\\s|$)").test(e);
641 };
642
643 $.getAll = function(o,r) {
644         r = r || [];
645         var s = o.childNodes;
646         for ( var i = 0; i < s.length; i++ )
647                 if ( s[i].nodeType == 1 ) {
648                         r[r.length] = s[i];
649                         $.getAll( s[i], r );
650                 }
651         return r;
652 };
653
654 $.merge = function(a,b) {
655         var d = [];
656         for ( var k = 0; k < b.length; k++ ) d[k] = b[k];
657
658         for ( var i = 0; i < a.length; i++ ) {
659                 var c = true;
660                 for ( var j = 0; j < b.length; j++ )
661                         if ( a[i] == b[j] )
662                                 c = false;
663                 if ( c ) d[d.length] = a[i];
664         }
665
666         return d;
667 };
668
669 $.grep = function(a,f,s) {
670         if ( f.constructor == String )
671                 f = new Function("a","i","return " + f);
672         var r = [];
673         if ( a != undefined )
674                 for ( var i = 0; i < a.length; i++ )
675                         if ( (!s && f(a[i],i)) || (s && !f(a[i],i)) )
676                                 r[r.length] = a[i];
677         return r;
678 };
679
680 $.map = function(a,f) {
681         if ( f.constructor == String )
682                 f = new Function("a","return " + f);
683         
684         var r = [];
685         for ( var i = 0; i < a.length; i++ ) {
686                 var t = f(a[i],i);
687                 if ( t !== null ) {
688                         if ( t.constructor != Array ) t = [t];
689                         r = $.merge( t, r );
690                 }
691         }
692         return r;
693 };
694
695 $.event = {};
696
697 // Bind an event to an element
698 // Original by Dean Edwards
699 $.event.add = function(element, type, handler) {
700         // For whatever reason, IE has trouble passing the window object
701         // around, causing it to be cloned in the process
702         if ( $.browser == "msie" && element.setInterval != undefined )
703                 element = window;
704
705         if (!handler.$$guid) handler.$$guid = $.event.add.guid++;
706         if (!element.events) element.events = {};
707         var handlers = element.events[type];
708         if (!handlers) {
709                 handlers = element.events[type] = {};
710                 if (element["on" + type])
711                         handlers[0] = element["on" + type];
712         }
713         handlers[handler.$$guid] = handler;
714         element["on" + type] = $.event.handle;
715 };
716
717 $.event.add.guid = 1;
718
719 // Detach an event or set of events from an element
720 $.event.remove = function(element, type, handler) {
721         if (element.events)
722                 if (type && element.events[type])
723                         if ( handler )
724                                 delete element.events[type][handler.$$guid];
725                         else
726                                 for ( var i in element.events[type] )
727                                         delete element.events[type][i];
728                 else
729                         for ( var j in element.events )
730                                 $.event.remove( element, j );
731 };
732
733 $.event.trigger = function(element,type,data) {
734         data = data || [ $.event.fix({ type: type }) ];
735         if ( element && element["on" + type] )
736                 element["on" + type].apply( element, data );
737 };
738
739 $.event.handle = function(event) {
740         if ( !event && !window.event ) return;
741
742         var returnValue = true, handlers = [];
743         event = event || $.event.fix(window.event);
744
745         for ( var j in this.events[event.type] )
746                 handlers[handlers.length] = this.events[event.type][j];
747
748         for ( var i = 0; i < handlers.length; i++ ) {
749                 if ( handlers[i].constructor == Function ) {
750                         this.$$handleEvent = handlers[i];
751                         if (this.$$handleEvent(event) === false) {
752                                 event.preventDefault();
753                                 event.stopPropagation();
754                                 returnValue = false;
755                         }
756                 }
757         }
758         return returnValue;
759 };
760
761 $.event.fix = function(event) {
762         event.preventDefault = $.event.fix.preventDefault;
763         event.stopPropagation = $.event.fix.stopPropagation;
764         return event;
765 };
766
767 $.event.fix.preventDefault = function() {
768         this.returnValue = false;
769 };
770
771 $.event.fix.stopPropagation = function() {
772         this.cancelBubble = true;
773 };