diff --git a/jquery.js b/jquery.js index 28eb907..9d1ad46 100644 --- a/jquery.js +++ b/jquery.js @@ -1,6 +1,6 @@ -(function(){ +(function(){ /* - * jQuery 1.2.1 - New Wave Javascript + * jQuery 1.2.1 - fresh New Wave Javascript * * Copyright (c) 2007 John Resig (jquery.com) * Dual licensed under the MIT (MIT-LICENSE.txt) @@ -1316,1859 +1316,1859 @@ jQuery.each([ "Height", "Width" ], function(i, name){ this.css( type, size.constructor == String ? size : size + "px" ); }; }); - -var chars = jQuery.browser.safari && parseInt(jQuery.browser.version) < 417 ? - "(?:[\\w*_-]|\\\\.)" : - "(?:[\\w\u0128-\uFFFF*_-]|\\\\.)", - quickChild = new RegExp("^>\\s*(" + chars + "+)"), - quickID = new RegExp("^(" + chars + "+)(#)(" + chars + "+)"), - quickClass = new RegExp("^([#.]?)(" + chars + "*)"); - -jQuery.extend({ - expr: { - "": "m[2]=='*'||jQuery.nodeName(a,m[2])", - "#": "a.getAttribute('id')==m[2]", - ":": { - // Position Checks - lt: "im[3]-0", - nth: "m[3]-0==i", - eq: "m[3]-0==i", - first: "i==0", - last: "i==r.length-1", - even: "i%2==0", - odd: "i%2", - - // Child Checks - "first-child": "a.parentNode.getElementsByTagName('*')[0]==a", - "last-child": "jQuery.nth(a.parentNode.lastChild,1,'previousSibling')==a", - "only-child": "!jQuery.nth(a.parentNode.lastChild,2,'previousSibling')", - - // Parent Checks - parent: "a.firstChild", - empty: "!a.firstChild", - - // Text Check - contains: "(a.textContent||a.innerText||jQuery(a).text()||'').indexOf(m[3])>=0", - - // Visibility - visible: '"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden"', - hidden: '"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden"', - - // Form attributes - enabled: "!a.disabled", - disabled: "a.disabled", - checked: "a.checked", - selected: "a.selected||jQuery.attr(a,'selected')", - - // Form elements - text: "'text'==a.type", - radio: "'radio'==a.type", - checkbox: "'checkbox'==a.type", - file: "'file'==a.type", - password: "'password'==a.type", - submit: "'submit'==a.type", - image: "'image'==a.type", - reset: "'reset'==a.type", - button: '"button"==a.type||jQuery.nodeName(a,"button")', - input: "/input|select|textarea|button/i.test(a.nodeName)", - - // :has() - has: "jQuery.find(m[3],a).length", - - // :header - header: "/h\\d/i.test(a.nodeName)", - - // :animated - animated: "jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length" - } - }, - - // The regular expressions that power the parsing engine - parse: [ - // Match: [@value='test'], [@foo] - /^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/, - - // Match: :contains('foo') - /^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/, - - // Match: :even, :last-chlid, #id, .class - new RegExp("^([:.#]*)(" + chars + "+)") - ], - - multiFilter: function( expr, elems, not ) { - var old, cur = []; - - while ( expr && expr != old ) { - old = expr; - var f = jQuery.filter( expr, elems, not ); - expr = f.t.replace(/^\s*,\s*/, "" ); - cur = not ? elems = f.r : jQuery.merge( cur, f.r ); - } - - return cur; - }, - - find: function( t, context ) { - // Quickly handle non-string expressions - if ( typeof t != "string" ) - return [ t ]; - - // Make sure that the context is a DOM Element - if ( context && !context.nodeType ) - context = null; - - // Set the correct context (if none is provided) - context = context || document; - - // Initialize the search - var ret = [context], done = [], last; - - // Continue while a selector expression exists, and while - // we're no longer looping upon ourselves - while ( t && last != t ) { - var r = []; - last = t; - - t = jQuery.trim(t); - - var foundToken = false; - - // An attempt at speeding up child selectors that - // point to a specific element tag - var re = quickChild; - var m = re.exec(t); - - if ( m ) { - var nodeName = m[1].toUpperCase(); - - // Perform our own iteration and filter - for ( var i = 0; ret[i]; i++ ) - for ( var c = ret[i].firstChild; c; c = c.nextSibling ) - if ( c.nodeType == 1 && (nodeName == "*" || c.nodeName.toUpperCase() == nodeName.toUpperCase()) ) - r.push( c ); - - ret = r; - t = t.replace( re, "" ); - if ( t.indexOf(" ") == 0 ) continue; - foundToken = true; - } else { - re = /^([>+~])\s*(\w*)/i; - - if ( (m = re.exec(t)) != null ) { - r = []; - - var nodeName = m[2], merge = {}; - m = m[1]; - - for ( var j = 0, rl = ret.length; j < rl; j++ ) { - var n = m == "~" || m == "+" ? ret[j].nextSibling : ret[j].firstChild; - for ( ; n; n = n.nextSibling ) - if ( n.nodeType == 1 ) { - var id = jQuery.data(n); - - if ( m == "~" && merge[id] ) break; - - if (!nodeName || n.nodeName.toUpperCase() == nodeName.toUpperCase() ) { - if ( m == "~" ) merge[id] = true; - r.push( n ); - } - - if ( m == "+" ) break; - } - } - - ret = r; - - // And remove the token - t = jQuery.trim( t.replace( re, "" ) ); - foundToken = true; - } - } - - // See if there's still an expression, and that we haven't already - // matched a token - if ( t && !foundToken ) { - // Handle multiple expressions - if ( !t.indexOf(",") ) { - // Clean the result set - if ( context == ret[0] ) ret.shift(); - - // Merge the result sets - done = jQuery.merge( done, ret ); - - // Reset the context - r = ret = [context]; - - // Touch up the selector string - t = " " + t.substr(1,t.length); - - } else { - // Optimize for the case nodeName#idName - var re2 = quickID; - var m = re2.exec(t); - - // Re-organize the results, so that they're consistent - if ( m ) { - m = [ 0, m[2], m[3], m[1] ]; - - } else { - // Otherwise, do a traditional filter check for - // ID, class, and element selectors - re2 = quickClass; - m = re2.exec(t); - } - - m[2] = m[2].replace(/\\/g, ""); - - var elem = ret[ret.length-1]; - - // Try to do a global search by ID, where we can - if ( m[1] == "#" && elem && elem.getElementById && !jQuery.isXMLDoc(elem) ) { - // Optimization for HTML document case - var oid = elem.getElementById(m[2]); - - // Do a quick check for the existence of the actual ID attribute - // to avoid selecting by the name attribute in IE - // also check to insure id is a string to avoid selecting an element with the name of 'id' inside a form - if ( (jQuery.browser.msie||jQuery.browser.opera) && oid && typeof oid.id == "string" && oid.id != m[2] ) - oid = jQuery('[@id="'+m[2]+'"]', elem)[0]; - - // Do a quick check for node name (where applicable) so - // that div#foo searches will be really fast - ret = r = oid && (!m[3] || jQuery.nodeName(oid, m[3])) ? [oid] : []; - } else { - // We need to find all descendant elements - for ( var i = 0; ret[i]; i++ ) { - // Grab the tag name being searched for - var tag = m[1] == "#" && m[3] ? m[3] : m[1] != "" || m[0] == "" ? "*" : m[2]; - - // Handle IE7 being really dumb about s - if ( tag == "*" && ret[i].nodeName.toLowerCase() == "object" ) - tag = "param"; - - r = jQuery.merge( r, ret[i].getElementsByTagName( tag )); - } - - // It's faster to filter by class and be done with it - if ( m[1] == "." ) - r = jQuery.classFilter( r, m[2] ); - - // Same with ID filtering - if ( m[1] == "#" ) { - var tmp = []; - - // Try to find the element with the ID - for ( var i = 0; r[i]; i++ ) - if ( r[i].getAttribute("id") == m[2] ) { - tmp = [ r[i] ]; - break; - } - - r = tmp; - } - - ret = r; - } - - t = t.replace( re2, "" ); - } - - } - - // If a selector string still exists - if ( t ) { - // Attempt to filter it - var val = jQuery.filter(t,r); - ret = r = val.r; - t = jQuery.trim(val.t); - } - } - - // An error occurred with the selector; - // just return an empty set instead - if ( t ) - ret = []; - - // Remove the root context - if ( ret && context == ret[0] ) - ret.shift(); - - // And combine the results - done = jQuery.merge( done, ret ); - - return done; - }, - - classFilter: function(r,m,not){ - m = " " + m + " "; - var tmp = []; - for ( var i = 0; r[i]; i++ ) { - var pass = (" " + r[i].className + " ").indexOf( m ) >= 0; - if ( !not && pass || not && !pass ) - tmp.push( r[i] ); - } - return tmp; - }, - - filter: function(t,r,not) { - var last; - - // Look for common filter expressions - while ( t && t != last ) { - last = t; - - var p = jQuery.parse, m; - - for ( var i = 0; p[i]; i++ ) { - m = p[i].exec( t ); - - if ( m ) { - // Remove what we just matched - t = t.substring( m[0].length ); - - m[2] = m[2].replace(/\\/g, ""); - break; - } - } - - if ( !m ) - break; - - // :not() is a special case that can be optimized by - // keeping it out of the expression list - if ( m[1] == ":" && m[2] == "not" ) - r = jQuery.filter(m[3], r, true).r; - - // We can get a big speed boost by filtering by class here - else if ( m[1] == "." ) - r = jQuery.classFilter(r, m[2], not); - - else if ( m[1] == "[" ) { - var tmp = [], type = m[3]; - - for ( var i = 0, rl = r.length; i < rl; i++ ) { - var a = r[i], z = a[ jQuery.props[m[2]] || m[2] ]; - - if ( z == null || /href|src|selected/.test(m[2]) ) - z = jQuery.attr(a,m[2]) || ''; - - if ( (type == "" && !!z || - type == "=" && z == m[5] || - type == "!=" && z != m[5] || - type == "^=" && z && !z.indexOf(m[5]) || - type == "$=" && z.substr(z.length - m[5].length) == m[5] || - (type == "*=" || type == "~=") && z.indexOf(m[5]) >= 0) ^ not ) - tmp.push( a ); - } - - r = tmp; - - // We can get a speed boost by handling nth-child here - } else if ( m[1] == ":" && m[2] == "nth-child" ) { - var merge = {}, tmp = [], - test = /(\d*)n\+?(\d*)/.exec( - m[3] == "even" && "2n" || m[3] == "odd" && "2n+1" || - !/\D/.test(m[3]) && "n+" + m[3] || m[3]), - first = (test[1] || 1) - 0, last = test[2] - 0; - - for ( var i = 0, rl = r.length; i < rl; i++ ) { - var node = r[i], parentNode = node.parentNode, id = jQuery.data(parentNode); - - if ( !merge[id] ) { - var c = 1; - - for ( var n = parentNode.firstChild; n; n = n.nextSibling ) - if ( n.nodeType == 1 ) - n.nodeIndex = c++; - - merge[id] = true; - } - - var add = false; - - if ( first == 1 ) { - if ( last == 0 || node.nodeIndex == last ) - add = true; - } else if ( (node.nodeIndex + last) % first == 0 ) - add = true; - - if ( add ^ not ) - tmp.push( node ); - } - - r = tmp; - - // Otherwise, find the expression to execute - } else { - var f = jQuery.expr[m[1]]; - if ( typeof f != "string" ) - f = jQuery.expr[m[1]][m[2]]; - - // Build a custom macro to enclose it - f = eval("false||function(a,i){return " + f + "}"); - - // Execute it against the current filter - r = jQuery.grep( r, f, not ); - } - } - - // Return an array of filtered elements (r) - // and the modified expression string (t) - return { r: r, t: t }; - }, - - dir: function( elem, dir ){ - var matched = []; - var cur = elem[dir]; - while ( cur && cur != document ) { - if ( cur.nodeType == 1 ) - matched.push( cur ); - cur = cur[dir]; - } - return matched; - }, - - nth: function(cur,result,dir,elem){ - result = result || 1; - var num = 0; - - for ( ; cur; cur = cur[dir] ) - if ( cur.nodeType == 1 && ++num == result ) - break; - - return cur; - }, - - sibling: function( n, elem ) { - var r = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType == 1 && (!elem || n != elem) ) - r.push( n ); - } - - return r; - } -}); -/* - * A number of helper functions used for managing events. - * Many of the ideas behind this code orignated from - * Dean Edwards' addEvent library. - */ -jQuery.event = { - - // Bind an event to an element - // Original by Dean Edwards - 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; - - // Make sure that the function being executed has a unique ID - if ( !handler.guid ) - handler.guid = this.guid++; - - // if data is passed, bind to handler - if( data != undefined ) { - // Create temporary function pointer to original handler - var fn = handler; - - // Create unique handler function, wrapped around original handler - handler = function() { - // Pass arguments and context to original handler - return fn.apply(this, arguments); - }; - - // Store data in unique handler - handler.data = data; - - // Set the guid of unique handler to the same of original handler, so it can be removed - handler.guid = fn.guid; - } - - // Namespaced event handlers - var parts = type.split("."); - type = parts[0]; - handler.type = parts[1]; - - // Init the element's event structure - var events = jQuery.data(element, "events") || jQuery.data(element, "events", {}); - - var handle = jQuery.data(element, "handle") || jQuery.data(element, "handle", function(){ - // returned undefined or false - var val; - - // Handle the second event of a trigger and when - // an event is called after a page has unloaded - if ( typeof jQuery == "undefined" || jQuery.event.triggered ) - return val; - - val = jQuery.event.handle.apply(element, arguments); - - return val; - }); - - // Get the current list of functions bound to this event - var handlers = events[type]; - - // Init the event handler queue - if (!handlers) { - handlers = events[type] = {}; - - // And bind the global event handler to the element - if (element.addEventListener) - element.addEventListener(type, handle, false); - else - element.attachEvent("on" + type, handle); - } - - // Add the function to the element's handler list - handlers[handler.guid] = handler; - - // Keep track of which events have been used, for global triggering - this.global[type] = true; - }, - - guid: 1, - global: {}, - - // Detach an event or set of events from an element - remove: function(element, type, handler) { - var events = jQuery.data(element, "events"), ret, index; - - // Namespaced event handlers - if ( typeof type == "string" ) { - var parts = type.split("."); - type = parts[0]; - } - - if ( events ) { - // type is actually an event object here - if ( type && type.type ) { - handler = type.handler; - type = type.type; - } - - if ( !type ) { - for ( type in events ) - this.remove( element, type ); - - } else if ( events[type] ) { - // remove the given handler for the given type - if ( handler ) - delete events[type][handler.guid]; - - // remove all handlers for the given type - else - for ( handler in events[type] ) - // Handle the removal of namespaced events - if ( !parts[1] || events[type][handler].type == parts[1] ) - delete events[type][handler]; - - // remove generic event handler if no more handlers exist - for ( ret in events[type] ) break; - if ( !ret ) { - if (element.removeEventListener) - element.removeEventListener(type, jQuery.data(element, "handle"), false); - else - element.detachEvent("on" + type, jQuery.data(element, "handle")); - ret = null; - delete events[type]; - } - } - - // Remove the expando if it's no longer used - for ( ret in events ) break; - if ( !ret ) { - jQuery.removeData( element, "events" ); - jQuery.removeData( element, "handle" ); - } - } - }, - - trigger: function(type, data, element, donative, extra) { - // Clone the incoming data, if any - data = jQuery.makeArray(data || []); - - // Handle a global trigger - if ( !element ) { - // Only trigger if we've ever bound an event for it - if ( this.global[type] ) - jQuery("*").add([window, document]).trigger(type, data); - - // Handle triggering a single element - } else { - var val, ret, fn = jQuery.isFunction( element[ type ] || null ), - // Check to see if we need to provide a fake event, or not - event = !data[0] || !data[0].preventDefault; - - // Pass along a fake event - if ( event ) - data.unshift( this.fix({ type: type, target: element }) ); - - // Enforce the right trigger type - data[0].type = type; - - // Trigger the event - if ( jQuery.isFunction( jQuery.data(element, "handle") ) ) - val = jQuery.data(element, "handle").apply( element, data ); - - // Handle triggering native .onfoo handlers - if ( !fn && element["on"+type] && element["on"+type].apply( element, data ) === false ) - val = false; - - // Extra functions don't get the custom event object - if ( event ) - data.shift(); - - // Handle triggering of extra function - if ( extra && extra.apply( element, data ) === false ) - val = false; - - // Trigger the native events (except for clicks on links) - if ( fn && donative !== false && val !== false && !(jQuery.nodeName(element, 'a') && type == "click") ) { - this.triggered = true; - element[ type ](); - } - - this.triggered = false; - } - - return val; - }, - - handle: function(event) { - // returned undefined or false - var val; - - // Empty object is for triggered events with no data - event = jQuery.event.fix( event || window.event || {} ); - - // Namespaced event handlers - var parts = event.type.split("."); - event.type = parts[0]; - - var handlers = jQuery.data(this, "events") && jQuery.data(this, "events")[event.type], args = Array.prototype.slice.call( arguments, 1 ); - args.unshift( event ); - - for ( var j in handlers ) { - var handler = handlers[j]; - // Pass in a reference to the handler function itself - // So that we can later remove it - args[0].handler = handler; - args[0].data = handler.data; - - // Filter the functions by class - if ( !parts[1] || handler.type == parts[1] ) { - var ret = handler.apply( this, args ); - - if ( val !== false ) - val = ret; - - if ( ret === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - - // Clean up added properties in IE to prevent memory leak - if (jQuery.browser.msie) - event.target = event.preventDefault = event.stopPropagation = - event.handler = event.data = null; - - return val; - }, - - fix: function(event) { - // store a copy of the original event object - // and clone to set read-only properties - var originalEvent = event; - event = jQuery.extend({}, originalEvent); - - // add preventDefault and stopPropagation since - // they will not work on the clone - event.preventDefault = function() { - // if preventDefault exists run it on the original event - if (originalEvent.preventDefault) - originalEvent.preventDefault(); - // otherwise set the returnValue property of the original event to false (IE) - originalEvent.returnValue = false; - }; - event.stopPropagation = function() { - // if stopPropagation exists run it on the original event - if (originalEvent.stopPropagation) - originalEvent.stopPropagation(); - // otherwise set the cancelBubble property of the original event to true (IE) - originalEvent.cancelBubble = true; - }; - - // Fix target property, if necessary - if ( !event.target && event.srcElement ) - event.target = event.srcElement; - - // check if target is a textnode (safari) - if (jQuery.browser.safari && event.target.nodeType == 3) - event.target = originalEvent.target.parentNode; - - // Add relatedTarget, if necessary - if ( !event.relatedTarget && event.fromElement ) - event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement; - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && event.clientX != null ) { - var doc = document.documentElement, body = document.body; - event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0); - event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientLeft || 0); - } - - // Add which for key events - if ( !event.which && (event.charCode || event.keyCode) ) - event.which = event.charCode || event.keyCode; - - // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) - if ( !event.metaKey && event.ctrlKey ) - event.metaKey = event.ctrlKey; - - // Add which for click: 1 == left; 2 == middle; 3 == right - // Note: button is not normalized, so don't use it - if ( !event.which && event.button ) - event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); - - return event; - } -}; - -jQuery.fn.extend({ - bind: function( type, data, fn ) { - return type == "unload" ? this.one(type, data, fn) : this.each(function(){ - jQuery.event.add( this, type, fn || data, fn && data ); - }); - }, - - one: function( type, data, fn ) { - return this.each(function(){ - jQuery.event.add( this, type, function(event) { - jQuery(this).unbind(event); - return (fn || data).apply( this, arguments); - }, fn && data); - }); - }, - - unbind: function( type, fn ) { - return this.each(function(){ - jQuery.event.remove( this, type, fn ); - }); - }, - - trigger: function( type, data, fn ) { - return this.each(function(){ - jQuery.event.trigger( type, data, this, true, fn ); - }); - }, - - triggerHandler: function( type, data, fn ) { - if ( this[0] ) - return jQuery.event.trigger( type, data, this[0], false, fn ); - }, - - toggle: function() { - // Save reference to arguments for access in closure - var args = arguments; - - return this.click(function(event) { - // Figure out which function to execute - this.lastToggle = 0 == this.lastToggle ? 1 : 0; - - // Make sure that clicks stop - event.preventDefault(); - - // and execute the function - return args[this.lastToggle].apply( this, [event] ) || false; - }); - }, - - hover: function(fnOver, fnOut) { - - // A private function for handling mouse 'hovering' - function handleHover(event) { - // Check if mouse(over|out) are still within the same parent element - var parent = event.relatedTarget; - - // Traverse up the tree - while ( parent && parent != this ) try { parent = parent.parentNode; } catch(error) { parent = this; }; - - // If we actually just moused on to a sub-element, ignore it - if ( parent == this ) return false; - - // Execute the right function - return (event.type == "mouseover" ? fnOver : fnOut).apply(this, [event]); - } - - // Bind the function to the two event listeners - return this.mouseover(handleHover).mouseout(handleHover); - }, - - ready: function(fn) { - // Attach the listeners - bindReady(); - - // If the DOM is already ready - if ( jQuery.isReady ) - // Execute the function immediately - fn.apply( document, [jQuery] ); - - // Otherwise, remember the function for later - else - // Add the function to the wait list - jQuery.readyList.push( function() { return fn.apply(this, [jQuery]); } ); - - return this; - } -}); - -jQuery.extend({ - /* - * All the code that makes DOM Ready work nicely. - */ - isReady: false, - readyList: [], - - // Handle when the DOM is ready - ready: function() { - // Make sure that the DOM is not already loaded - if ( !jQuery.isReady ) { - // Remember that the DOM is ready - jQuery.isReady = true; - - // If there are functions bound, to execute - if ( jQuery.readyList ) { - // Execute all of them - jQuery.each( jQuery.readyList, function(){ - this.apply( document ); - }); - - // Reset the list of functions - jQuery.readyList = null; - } - // Remove event listener to avoid memory leak - if ( jQuery.browser.mozilla || jQuery.browser.opera ) - document.removeEventListener( "DOMContentLoaded", jQuery.ready, false ); - } - } -}); - - -jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," + - "mousedown,mouseup,mousemove,mouseover,mouseout,change,select," + - "submit,keydown,keypress,keyup,error").split(","), function(i, name){ - - // Handle event binding - jQuery.fn[name] = function(fn){ - return fn ? this.bind(name, fn) : this.trigger(name); - }; -}); - -var readyBound = false; - -function bindReady(){ - if ( readyBound ) return; - readyBound = true; - - // If Mozilla is used - if ( jQuery.browser.mozilla || jQuery.browser.opera ) - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", jQuery.ready, false ); - - // If Safari or IE is used - // Continually check to see if the document is ready - else (function(){ - try { - // If IE is used, use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - if ( jQuery.browser.msie || document.readyState != "loaded" && document.readyState != "complete" ) - document.documentElement.doScroll("left"); - } catch( error ) { - return setTimeout( arguments.callee, 0 ); - } - - // and execute any waiting functions - jQuery.ready(); - })(); - - // A fallback to window.onload, that will always work - jQuery.event.add( window, "load", jQuery.ready ); -} - -// Prevent memory leaks in IE -if ( jQuery.browser.msie ) - jQuery(window).bind("unload", function() { - $("*").add([document, window]).unbind(); - }); -jQuery.fn.extend({ - load: function( url, params, callback ) { - if ( jQuery.isFunction( url ) ) - return this.bind("load", url); - - var off = url.indexOf(" "); - if ( off >= 0 ) { - var selector = url.slice(off, url.length); - url = url.slice(0, off); - } - - callback = callback || function(){}; - - // Default to a GET request - var type = "GET"; - - // If the second parameter was provided - if ( params ) - // If it's a function - if ( jQuery.isFunction( params ) ) { - // We assume that it's the callback - callback = params; - params = null; - - // Otherwise, build a param string - } else { - params = jQuery.param( params ); - type = "POST"; - } - - var self = this; - - // Request the remote document - jQuery.ajax({ - url: url, - type: type, - data: params, - complete: function(res, status){ - // If successful, inject the HTML into all the matched elements - if ( status == "success" || status == "notmodified" ) - // See if a selector was specified - self.html( selector ? - // Create a dummy div to hold the results - jQuery("
") - // inject the contents of the document in, removing the scripts - // to avoid any 'Permission Denied' errors in IE - .append(res.responseText.replace(//g, "")) - - // Locate the specified elements - .find(selector) : - - // If not, just inject the full result - res.responseText ); - - // Add delay to account for Safari's delay in globalEval - setTimeout(function(){ - self.each( callback, [res.responseText, status, res] ); - }, 13); - } - }); - return this; - }, - - serialize: function() { - return jQuery.param(this.serializeArray()); - }, - serializeArray: function() { - return this.map(function(){ - return jQuery.nodeName(this, "form") ? - jQuery.makeArray(this.elements) : this; - }) - .filter(function(){ - return this.name && !this.disabled && - (this.checked || /select|textarea/i.test(this.nodeName) || - /text|hidden|password/i.test(this.type)); - }) - .map(function(i, elem){ - var val = jQuery(this).val(); - return val == null ? null : - val.constructor == Array ? - jQuery.map( val, function(val, i){ - return {name: elem.name, value: val}; - }) : - {name: elem.name, value: val}; - }).get(); - } -}); - -// Attach a bunch of functions for handling common AJAX events -jQuery.each( "ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","), function(i,o){ - jQuery.fn[o] = function(f){ - return this.bind(o, f); - }; -}); - -var jsc = (new Date).getTime(); - -jQuery.extend({ - get: function( url, data, callback, type ) { - // shift arguments if data argument was ommited - if ( jQuery.isFunction( data ) ) { - callback = data; - data = null; - } - - return jQuery.ajax({ - type: "GET", - url: url, - data: data, - success: callback, - dataType: type - }); - }, - - getScript: function( url, callback ) { - return jQuery.get(url, null, callback, "script"); - }, - - getJSON: function( url, data, callback ) { - return jQuery.get(url, data, callback, "json"); - }, - - post: function( url, data, callback, type ) { - if ( jQuery.isFunction( data ) ) { - callback = data; - data = {}; - } - - return jQuery.ajax({ - type: "POST", - url: url, - data: data, - success: callback, - dataType: type - }); - }, - - ajaxSetup: function( settings ) { - jQuery.extend( jQuery.ajaxSettings, settings ); - }, - - ajaxSettings: { - global: true, - type: "GET", - timeout: 0, - contentType: "application/x-www-form-urlencoded", - processData: true, - async: true, - data: null - }, - - // Last-Modified header cache for next request - lastModified: {}, - - ajax: function( s ) { - var jsonp, jsre = /=(\?|%3F)/g, status, data; - - // Extend the settings, but re-extend 's' so that it can be - // checked again later (in the test suite, specifically) - s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s)); - - // convert data if not already a string - if ( s.data && s.processData && typeof s.data != "string" ) - s.data = jQuery.param(s.data); - - // Handle JSONP Parameter Callbacks - if ( s.dataType == "jsonp" ) { - if ( s.type.toLowerCase() == "get" ) { - if ( !s.url.match(jsre) ) - s.url += (s.url.match(/\?/) ? "&" : "?") + (s.jsonp || "callback") + "=?"; - } else if ( !s.data || !s.data.match(jsre) ) - s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?"; - s.dataType = "json"; - } - - // Build temporary JSONP function - if ( s.dataType == "json" && (s.data && jsre.test( s.data ) || s.url.match(jsre)) ) { - jsonp = "jsonp" + jsc++; - - // Replace the =? sequence both in the query string and the data - if ( s.data ) - s.data = (s.data + "").replace(jsre, "=" + jsonp); - s.url = s.url.replace(jsre, "=" + jsonp); - - // We need to make sure - // that a JSONP style response is executed properly - s.dataType = "script"; - - // Handle JSONP-style loading - window[ jsonp ] = function(tmp){ - data = tmp; - success(); - complete(); - // Garbage collect - window[ jsonp ] = undefined; - try{ delete window[ jsonp ]; } catch(e){} - }; - } - - if ( s.dataType == "script" && s.cache == null ) - s.cache = false; - - if ( s.cache === false && s.type.toLowerCase() == "get" ) - s.url += (s.url.match(/\?/) ? "&" : "?") + "_=" + (new Date()).getTime(); - - // If data is available, append data to url for get requests - if ( s.data && s.type.toLowerCase() == "get" ) { - s.url += (s.url.match(/\?/) ? "&" : "?") + s.data; - - // IE likes to send both get and post data, prevent this - s.data = null; - } - - // Watch for a new set of requests - if ( s.global && ! jQuery.active++ ) - jQuery.event.trigger( "ajaxStart" ); - - // If we're requesting a remote document - // and trying to load JSON or Script - if ( !s.url.indexOf("http") && s.dataType == "script" ) { - var head = document.getElementsByTagName("head")[0]; - var script = document.createElement("script"); - script.src = s.url; - - // Handle Script loading - if ( !jsonp ) { - var done = false; - - // Attach handlers for all browsers - script.onload = script.onreadystatechange = function(){ - if ( !done && (!this.readyState || - this.readyState == "loaded" || this.readyState == "complete") ) { - done = true; - success(); - complete(); - head.removeChild( script ); - } - }; - } - - head.appendChild(script); - - // We handle everything using the script element injection - return; - } - - var requestDone = false; - - // Create the request object; Microsoft failed to properly - // implement the XMLHttpRequest in IE7, so we use the ActiveXObject when it is available - var xml = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest(); - - // Open the socket - xml.open(s.type, s.url, s.async); - - // Set the correct header, if data is being sent - if ( s.data ) - xml.setRequestHeader("Content-Type", s.contentType); - - // Set the If-Modified-Since header, if ifModified mode. - if ( s.ifModified ) - xml.setRequestHeader("If-Modified-Since", - jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" ); - - // Set header so the called script knows that it's an XMLHttpRequest - xml.setRequestHeader("X-Requested-With", "XMLHttpRequest"); - - // Allow custom headers/mimetypes - if ( s.beforeSend ) - s.beforeSend(xml); - - if ( s.global ) - jQuery.event.trigger("ajaxSend", [xml, s]); - - // Wait for a response to come back - var onreadystatechange = function(isTimeout){ - // The transfer is complete and the data is available, or the request timed out - if ( !requestDone && xml && (xml.readyState == 4 || isTimeout == "timeout") ) { - requestDone = true; - - // clear poll interval - if (ival) { - clearInterval(ival); - ival = null; - } - - status = isTimeout == "timeout" && "timeout" || - !jQuery.httpSuccess( xml ) && "error" || - s.ifModified && jQuery.httpNotModified( xml, s.url ) && "notmodified" || - "success"; - - if ( status == "success" ) { - // Watch for, and catch, XML document parse errors - try { - // process the data (runs the xml through httpData regardless of callback) - data = jQuery.httpData( xml, s.dataType ); - } catch(e) { - status = "parsererror"; - } - } - - // Make sure that the request was successful or notmodified - if ( status == "success" ) { - // Cache Last-Modified header, if ifModified mode. - var modRes; - try { - modRes = xml.getResponseHeader("Last-Modified"); - } catch(e) {} // swallow exception thrown by FF if header is not available - - if ( s.ifModified && modRes ) - jQuery.lastModified[s.url] = modRes; - - // JSONP handles its own success callback - if ( !jsonp ) - success(); - } else - jQuery.handleError(s, xml, status); - - // Fire the complete handlers - complete(); - - // Stop memory leaks - if ( s.async ) - xml = null; - } - }; - - if ( s.async ) { - // don't attach the handler to the request, just poll it instead - var ival = setInterval(onreadystatechange, 13); - - // Timeout checker - if ( s.timeout > 0 ) - setTimeout(function(){ - // Check to see if the request is still happening - if ( xml ) { - // Cancel the request - xml.abort(); - - if( !requestDone ) - onreadystatechange( "timeout" ); - } - }, s.timeout); - } - - // Send the data - try { - xml.send(s.data); - } catch(e) { - jQuery.handleError(s, xml, null, e); - } - - // firefox 1.5 doesn't fire statechange for sync requests - if ( !s.async ) - onreadystatechange(); - - // return XMLHttpRequest to allow aborting the request etc. - return xml; - - function success(){ - // If a local callback was specified, fire it and pass it the data - if ( s.success ) - s.success( data, status ); - - // Fire the global callback - if ( s.global ) - jQuery.event.trigger( "ajaxSuccess", [xml, s] ); - } - - function complete(){ - // Process result - if ( s.complete ) - s.complete(xml, status); - - // The request was completed - if ( s.global ) - jQuery.event.trigger( "ajaxComplete", [xml, s] ); - - // Handle the global AJAX counter - if ( s.global && ! --jQuery.active ) - jQuery.event.trigger( "ajaxStop" ); - } - }, - - handleError: function( s, xml, status, e ) { - // If a local callback was specified, fire it - if ( s.error ) s.error( xml, status, e ); - - // Fire the global callback - if ( s.global ) - jQuery.event.trigger( "ajaxError", [xml, s, e] ); - }, - - // Counter for holding the number of active queries - active: 0, - - // Determines if an XMLHttpRequest was successful or not - httpSuccess: function( r ) { - try { - return !r.status && location.protocol == "file:" || - ( r.status >= 200 && r.status < 300 ) || r.status == 304 || - jQuery.browser.safari && r.status == undefined; - } catch(e){} - return false; - }, - - // Determines if an XMLHttpRequest returns NotModified - httpNotModified: function( xml, url ) { - try { - var xmlRes = xml.getResponseHeader("Last-Modified"); - - // Firefox always returns 200. check Last-Modified date - return xml.status == 304 || xmlRes == jQuery.lastModified[url] || - jQuery.browser.safari && xml.status == undefined; - } catch(e){} - return false; - }, - - httpData: function( r, type ) { - var ct = r.getResponseHeader("content-type"); - var xml = type == "xml" || !type && ct && ct.indexOf("xml") >= 0; - var data = xml ? r.responseXML : r.responseText; - - if ( xml && data.documentElement.tagName == "parsererror" ) - throw "parsererror"; - - // If the type is "script", eval it in global context - if ( type == "script" ) - jQuery.globalEval( data ); - - // Get the JavaScript object, if JSON is used. - if ( type == "json" ) - data = eval("(" + data + ")"); - - return data; - }, - - // Serialize an array of form elements or a set of - // key/values into a query string - param: function( a ) { - var s = []; - - // If an array was passed in, assume that it is an array - // of form elements - if ( a.constructor == Array || a.jquery ) - // Serialize the form elements - jQuery.each( a, function(){ - s.push( encodeURIComponent(this.name) + "=" + encodeURIComponent( this.value ) ); - }); - - // Otherwise, assume that it's an object of key/value pairs - else - // Serialize the key/values - for ( var j in a ) - // If the value is an array then the key names need to be repeated - if ( a[j] && a[j].constructor == Array ) - jQuery.each( a[j], function(){ - s.push( encodeURIComponent(j) + "=" + encodeURIComponent( this ) ); - }); - else - s.push( encodeURIComponent(j) + "=" + encodeURIComponent( a[j] ) ); - - // Return the resulting serialization - return s.join("&").replace(/%20/g, "+"); - } - -}); -jQuery.fn.extend({ - show: function(speed,callback){ - return speed ? - this.animate({ - height: "show", width: "show", opacity: "show" - }, speed, callback) : - - this.filter(":hidden").each(function(){ - this.style.display = this.oldblock ? this.oldblock : ""; - if ( jQuery.css(this,"display") == "none" ) - this.style.display = "block"; - }).end(); - }, - - hide: function(speed,callback){ - return speed ? - this.animate({ - height: "hide", width: "hide", opacity: "hide" - }, speed, callback) : - - this.filter(":visible").each(function(){ - this.oldblock = this.oldblock || jQuery.css(this,"display"); - if ( this.oldblock == "none" ) - this.oldblock = "block"; - this.style.display = "none"; - }).end(); - }, - - // Save the old toggle function - _toggle: jQuery.fn.toggle, - - toggle: function( fn, fn2 ){ - return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ? - this._toggle( fn, fn2 ) : - fn ? - this.animate({ - height: "toggle", width: "toggle", opacity: "toggle" - }, fn, fn2) : - this.each(function(){ - jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ](); - }); - }, - - slideDown: function(speed,callback){ - return this.animate({height: "show"}, speed, callback); - }, - - slideUp: function(speed,callback){ - return this.animate({height: "hide"}, speed, callback); - }, - - slideToggle: function(speed, callback){ - return this.animate({height: "toggle"}, speed, callback); - }, - - fadeIn: function(speed, callback){ - return this.animate({opacity: "show"}, speed, callback); - }, - - fadeOut: function(speed, callback){ - return this.animate({opacity: "hide"}, speed, callback); - }, - - fadeTo: function(speed,to,callback){ - return this.animate({opacity: to}, speed, callback); - }, - - animate: function( prop, speed, easing, callback ) { - var optall = jQuery.speed(speed, easing, callback); - - return this[ optall.queue === false ? "each" : "queue" ](function(){ - var opt = jQuery.extend({}, optall); - var hidden = jQuery(this).is(":hidden"), self = this; - - for ( var p in prop ) { - if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden ) - return jQuery.isFunction(opt.complete) && opt.complete.apply(this); - - if ( p == "height" || p == "width" ) { - // Store display property - opt.display = jQuery.css(this, "display"); - - // Make sure that nothing sneaks out - opt.overflow = this.style.overflow; - } - } - - if ( opt.overflow != null ) - this.style.overflow = "hidden"; - - opt.curAnim = jQuery.extend({}, prop); - - jQuery.each( prop, function(name, val){ - var e = new jQuery.fx( self, opt, name ); - - if ( /toggle|show|hide/.test(val) ) - e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop ); - else { - var parts = val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/), - start = e.cur(true) || 0; - - if ( parts ) { - var end = parseFloat(parts[2]), - unit = parts[3] || "px"; - - // We need to compute starting value - if ( unit != "px" ) { - self.style[ name ] = (end || 1) + unit; - start = ((end || 1) / e.cur(true)) * start; - self.style[ name ] = start + unit; - } - - // If a +=/-= token was provided, we're doing a relative animation - if ( parts[1] ) - end = ((parts[1] == "-=" ? -1 : 1) * end) + start; - - e.custom( start, end, unit ); - } else - e.custom( start, val, "" ); - } - }); - - // For JS strict compliance - return true; - }); - }, - - queue: function(type, fn){ - if ( jQuery.isFunction(type) ) { - fn = type; - type = "fx"; - } - - if ( !type || (typeof type == "string" && !fn) ) - return queue( this[0], type ); - - return this.each(function(){ - if ( fn.constructor == Array ) - queue(this, type, fn); - else { - queue(this, type).push( fn ); - - if ( queue(this, type).length == 1 ) - fn.apply(this); - } - }); - }, - - stop: function(){ - var timers = jQuery.timers; - - return this.each(function(){ - for ( var i = 0; i < timers.length; i++ ) - if ( timers[i].elem == this ) - timers.splice(i--, 1); - }).dequeue(); - } - -}); - -var queue = function( elem, type, array ) { - if ( !elem ) - return; - - var q = jQuery.data( elem, type + "queue" ); - - if ( !q || array ) - q = jQuery.data( elem, type + "queue", - array ? jQuery.makeArray(array) : [] ); - - return q; -}; - -jQuery.fn.dequeue = function(type){ - type = type || "fx"; - - return this.each(function(){ - var q = queue(this, type); - - q.shift(); - - if ( q.length ) - q[0].apply( this ); - }); -}; - -jQuery.extend({ - - speed: function(speed, easing, fn) { - var opt = speed && speed.constructor == Object ? speed : { - complete: fn || !fn && easing || - jQuery.isFunction( speed ) && speed, - duration: speed, - easing: fn && easing || easing && easing.constructor != Function && easing - }; - - opt.duration = (opt.duration && opt.duration.constructor == Number ? - opt.duration : - { slow: 600, fast: 200 }[opt.duration]) || 400; - - // Queueing - opt.old = opt.complete; - opt.complete = function(){ - jQuery(this).dequeue(); - if ( jQuery.isFunction( opt.old ) ) - opt.old.apply( this ); - }; - - return opt; - }, - - easing: { - linear: function( p, n, firstNum, diff ) { - return firstNum + diff * p; - }, - swing: function( p, n, firstNum, diff ) { - return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum; - } - }, - - timers: [], - - fx: function( elem, options, prop ){ - this.options = options; - this.elem = elem; - this.prop = prop; - - if ( !options.orig ) - options.orig = {}; - } - -}); - -jQuery.fx.prototype = { - - // Simple function for setting a style value - update: function(){ - if ( this.options.step ) - this.options.step.apply( this.elem, [ this.now, this ] ); - - (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this ); - - // Set display property to block for height/width animations - if ( this.prop == "height" || this.prop == "width" ) - this.elem.style.display = "block"; - }, - - // Get the current size - cur: function(force){ - if ( this.elem[this.prop] != null && this.elem.style[this.prop] == null ) - return this.elem[ this.prop ]; - - var r = parseFloat(jQuery.curCSS(this.elem, this.prop, force)); - return r && r > -10000 ? r : parseFloat(jQuery.css(this.elem, this.prop)) || 0; - }, - - // Start an animation from one number to another - custom: function(from, to, unit){ - this.startTime = (new Date()).getTime(); - this.start = from; - this.end = to; - this.unit = unit || this.unit || "px"; - this.now = this.start; - this.pos = this.state = 0; - this.update(); - - var self = this; - function t(){ - return self.step(); - } - - t.elem = this.elem; - - jQuery.timers.push(t); - - if ( jQuery.timers.length == 1 ) { - var timer = setInterval(function(){ - var timers = jQuery.timers; - - for ( var i = 0; i < timers.length; i++ ) - if ( !timers[i]() ) - timers.splice(i--, 1); - - if ( !timers.length ) - clearInterval( timer ); - }, 13); - } - }, - - // Simple 'show' function - show: function(){ - // Remember where we started, so that we can go back to it later - this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop ); - this.options.show = true; - - // Begin the animation - this.custom(0, this.cur()); - - // Make sure that we start at a small width/height to avoid any - // flash of content - if ( this.prop == "width" || this.prop == "height" ) - this.elem.style[this.prop] = "1px"; - - // Start by showing the element - jQuery(this.elem).show(); - }, - - // Simple 'hide' function - hide: function(){ - // Remember where we started, so that we can go back to it later - this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop ); - this.options.hide = true; - - // Begin the animation - this.custom(this.cur(), 0); - }, - - // Each step of an animation - step: function(){ - var t = (new Date()).getTime(); - - if ( t > this.options.duration + this.startTime ) { - this.now = this.end; - this.pos = this.state = 1; - this.update(); - - this.options.curAnim[ this.prop ] = true; - - var done = true; - for ( var i in this.options.curAnim ) - if ( this.options.curAnim[i] !== true ) - done = false; - - if ( done ) { - if ( this.options.display != null ) { - // Reset the overflow - this.elem.style.overflow = this.options.overflow; - - // Reset the display - this.elem.style.display = this.options.display; - if ( jQuery.css(this.elem, "display") == "none" ) - this.elem.style.display = "block"; - } - - // Hide the element if the "hide" operation was done - if ( this.options.hide ) - this.elem.style.display = "none"; - - // Reset the properties, if the item has been hidden or shown - if ( this.options.hide || this.options.show ) - for ( var p in this.options.curAnim ) - jQuery.attr(this.elem.style, p, this.options.orig[p]); - } - - // If a callback was provided, execute it - if ( done && jQuery.isFunction( this.options.complete ) ) - // Execute the complete function - this.options.complete.apply( this.elem ); - - return false; - } else { - var n = t - this.startTime; - this.state = n / this.options.duration; - - // Perform the easing function, defaults to swing - this.pos = jQuery.easing[this.options.easing || (jQuery.easing.swing ? "swing" : "linear")](this.state, n, 0, 1, this.options.duration); - this.now = this.start + ((this.end - this.start) * this.pos); - - // Perform the next step of the animation - this.update(); - } - - return true; - } - -}; - -jQuery.fx.step = { - scrollLeft: function(fx){ - fx.elem.scrollLeft = fx.now; - }, - - scrollTop: function(fx){ - fx.elem.scrollTop = fx.now; - }, - - opacity: function(fx){ - jQuery.attr(fx.elem.style, "opacity", fx.now); - }, - - _default: function(fx){ - fx.elem.style[ fx.prop ] = fx.now + fx.unit; - } -}; -// The Offset Method -// Originally By Brandon Aaron, part of the Dimension Plugin -// http://jquery.com/plugins/project/dimensions -jQuery.fn.offset = function() { - var left = 0, top = 0, elem = this[0], results; - - if ( elem ) with ( jQuery.browser ) { - var parent = elem.parentNode, - offsetChild = elem, - offsetParent = elem.offsetParent, - doc = elem.ownerDocument, - safari2 = safari && parseInt(version) < 522, - fixed = jQuery.css(elem, "position") == "fixed"; - - // Use getBoundingClientRect if available - if ( elem.getBoundingClientRect ) { - var box = elem.getBoundingClientRect(); - - // Add the document scroll offsets - add( - box.left + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft), - box.top + Math.max(doc.documentElement.scrollTop, doc.body.scrollTop) - ); - - // IE adds the HTML element's border, by default it is medium which is 2px - // IE 6 and IE 7 quirks mode the border width is overwritable by the following css html { border: 0; } - // IE 7 standards mode, the border is always 2px - if ( msie ) { - var border = jQuery("html").css("borderWidth"); - border = (border == "medium" || jQuery.boxModel && parseInt(version) >= 7) && 2 || border; - add( -border, -border ); - } - - // Otherwise loop through the offsetParents and parentNodes - } else { - - // Initial element offsets - add( elem.offsetLeft, elem.offsetTop ); - - // Get parent offsets - while ( offsetParent ) { - // Add offsetParent offsets - add( offsetParent.offsetLeft, offsetParent.offsetTop ); - - // Mozilla and Safari > 2 does not include the border on offset parents - // However Mozilla adds the border for table or table cells - if ( mozilla && !/^t(able|d|h)$/i.test(offsetParent.tagName) || safari && !safari2 ) - border( offsetParent ); - - // Add the document scroll offsets if position is fixed on any offsetParent - if ( !fixed && jQuery.css(offsetParent, "position") == "fixed" ) - fixed = true; - - // Set offsetChild to previous offsetParent unless it is the body element - offsetChild = /^body$/i.test(offsetParent.tagName) ? offsetChild : offsetParent; - // Get next offsetParent - offsetParent = offsetParent.offsetParent; - } - - // Get parent scroll offsets - while ( parent.tagName && !/^body|html$/i.test(parent.tagName) ) { - // Remove parent scroll UNLESS that parent is inline or a table-row to work around Opera inline/table scrollLeft/Top bug - if ( !/^inline|table-row.*$/i.test(jQuery.css(parent, "display")) ) - // Subtract parent scroll offsets - add( -parent.scrollLeft, -parent.scrollTop ); - - // Mozilla does not add the border for a parent that has overflow != visible - if ( mozilla && jQuery.css(parent, "overflow") != "visible" ) - border( parent ); - - // Get next parent - parent = parent.parentNode; - } - - // Safari <= 2 doubles body offsets with a fixed position element/offsetParent or absolutely positioned offsetChild - // Mozilla doubles body offsets with a non-absolutely positioned offsetChild - if ( (safari2 && (fixed || jQuery.css(offsetChild, "position") == "absolute")) || - (mozilla && jQuery.css(offsetChild, "position") != "absoltue") ) - add( -doc.body.offsetLeft, -doc.body.offsetTop ); - - // Add the document scroll offsets if position is fixed - if ( fixed ) - add( - Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft), - Math.max(doc.documentElement.scrollTop, doc.body.scrollTop) - ); - } - - // Return an object with top and left properties - results = { top: top, left: left }; - } - - return results; - - function border(elem) { - add( jQuery.css(elem, "borderLeftWidth"), jQuery.css(elem, "borderTopWidth") ); - } - - function add(l, t) { - left += parseInt(l) || 0; - top += parseInt(t) || 0; - } -}; -})(); + +var chars = jQuery.browser.safari && parseInt(jQuery.browser.version) < 417 ? + "(?:[\\w*_-]|\\\\.)" : + "(?:[\\w\u0128-\uFFFF*_-]|\\\\.)", + quickChild = new RegExp("^>\\s*(" + chars + "+)"), + quickID = new RegExp("^(" + chars + "+)(#)(" + chars + "+)"), + quickClass = new RegExp("^([#.]?)(" + chars + "*)"); + +jQuery.extend({ + expr: { + "": "m[2]=='*'||jQuery.nodeName(a,m[2])", + "#": "a.getAttribute('id')==m[2]", + ":": { + // Position Checks + lt: "im[3]-0", + nth: "m[3]-0==i", + eq: "m[3]-0==i", + first: "i==0", + last: "i==r.length-1", + even: "i%2==0", + odd: "i%2", + + // Child Checks + "first-child": "a.parentNode.getElementsByTagName('*')[0]==a", + "last-child": "jQuery.nth(a.parentNode.lastChild,1,'previousSibling')==a", + "only-child": "!jQuery.nth(a.parentNode.lastChild,2,'previousSibling')", + + // Parent Checks + parent: "a.firstChild", + empty: "!a.firstChild", + + // Text Check + contains: "(a.textContent||a.innerText||jQuery(a).text()||'').indexOf(m[3])>=0", + + // Visibility + visible: '"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden"', + hidden: '"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden"', + + // Form attributes + enabled: "!a.disabled", + disabled: "a.disabled", + checked: "a.checked", + selected: "a.selected||jQuery.attr(a,'selected')", + + // Form elements + text: "'text'==a.type", + radio: "'radio'==a.type", + checkbox: "'checkbox'==a.type", + file: "'file'==a.type", + password: "'password'==a.type", + submit: "'submit'==a.type", + image: "'image'==a.type", + reset: "'reset'==a.type", + button: '"button"==a.type||jQuery.nodeName(a,"button")', + input: "/input|select|textarea|button/i.test(a.nodeName)", + + // :has() + has: "jQuery.find(m[3],a).length", + + // :header + header: "/h\\d/i.test(a.nodeName)", + + // :animated + animated: "jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length" + } + }, + + // The regular expressions that power the parsing engine + parse: [ + // Match: [@value='test'], [@foo] + /^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/, + + // Match: :contains('foo') + /^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/, + + // Match: :even, :last-chlid, #id, .class + new RegExp("^([:.#]*)(" + chars + "+)") + ], + + multiFilter: function( expr, elems, not ) { + var old, cur = []; + + while ( expr && expr != old ) { + old = expr; + var f = jQuery.filter( expr, elems, not ); + expr = f.t.replace(/^\s*,\s*/, "" ); + cur = not ? elems = f.r : jQuery.merge( cur, f.r ); + } + + return cur; + }, + + find: function( t, context ) { + // Quickly handle non-string expressions + if ( typeof t != "string" ) + return [ t ]; + + // Make sure that the context is a DOM Element + if ( context && !context.nodeType ) + context = null; + + // Set the correct context (if none is provided) + context = context || document; + + // Initialize the search + var ret = [context], done = [], last; + + // Continue while a selector expression exists, and while + // we're no longer looping upon ourselves + while ( t && last != t ) { + var r = []; + last = t; + + t = jQuery.trim(t); + + var foundToken = false; + + // An attempt at speeding up child selectors that + // point to a specific element tag + var re = quickChild; + var m = re.exec(t); + + if ( m ) { + var nodeName = m[1].toUpperCase(); + + // Perform our own iteration and filter + for ( var i = 0; ret[i]; i++ ) + for ( var c = ret[i].firstChild; c; c = c.nextSibling ) + if ( c.nodeType == 1 && (nodeName == "*" || c.nodeName.toUpperCase() == nodeName.toUpperCase()) ) + r.push( c ); + + ret = r; + t = t.replace( re, "" ); + if ( t.indexOf(" ") == 0 ) continue; + foundToken = true; + } else { + re = /^([>+~])\s*(\w*)/i; + + if ( (m = re.exec(t)) != null ) { + r = []; + + var nodeName = m[2], merge = {}; + m = m[1]; + + for ( var j = 0, rl = ret.length; j < rl; j++ ) { + var n = m == "~" || m == "+" ? ret[j].nextSibling : ret[j].firstChild; + for ( ; n; n = n.nextSibling ) + if ( n.nodeType == 1 ) { + var id = jQuery.data(n); + + if ( m == "~" && merge[id] ) break; + + if (!nodeName || n.nodeName.toUpperCase() == nodeName.toUpperCase() ) { + if ( m == "~" ) merge[id] = true; + r.push( n ); + } + + if ( m == "+" ) break; + } + } + + ret = r; + + // And remove the token + t = jQuery.trim( t.replace( re, "" ) ); + foundToken = true; + } + } + + // See if there's still an expression, and that we haven't already + // matched a token + if ( t && !foundToken ) { + // Handle multiple expressions + if ( !t.indexOf(",") ) { + // Clean the result set + if ( context == ret[0] ) ret.shift(); + + // Merge the result sets + done = jQuery.merge( done, ret ); + + // Reset the context + r = ret = [context]; + + // Touch up the selector string + t = " " + t.substr(1,t.length); + + } else { + // Optimize for the case nodeName#idName + var re2 = quickID; + var m = re2.exec(t); + + // Re-organize the results, so that they're consistent + if ( m ) { + m = [ 0, m[2], m[3], m[1] ]; + + } else { + // Otherwise, do a traditional filter check for + // ID, class, and element selectors + re2 = quickClass; + m = re2.exec(t); + } + + m[2] = m[2].replace(/\\/g, ""); + + var elem = ret[ret.length-1]; + + // Try to do a global search by ID, where we can + if ( m[1] == "#" && elem && elem.getElementById && !jQuery.isXMLDoc(elem) ) { + // Optimization for HTML document case + var oid = elem.getElementById(m[2]); + + // Do a quick check for the existence of the actual ID attribute + // to avoid selecting by the name attribute in IE + // also check to insure id is a string to avoid selecting an element with the name of 'id' inside a form + if ( (jQuery.browser.msie||jQuery.browser.opera) && oid && typeof oid.id == "string" && oid.id != m[2] ) + oid = jQuery('[@id="'+m[2]+'"]', elem)[0]; + + // Do a quick check for node name (where applicable) so + // that div#foo searches will be really fast + ret = r = oid && (!m[3] || jQuery.nodeName(oid, m[3])) ? [oid] : []; + } else { + // We need to find all descendant elements + for ( var i = 0; ret[i]; i++ ) { + // Grab the tag name being searched for + var tag = m[1] == "#" && m[3] ? m[3] : m[1] != "" || m[0] == "" ? "*" : m[2]; + + // Handle IE7 being really dumb about s + if ( tag == "*" && ret[i].nodeName.toLowerCase() == "object" ) + tag = "param"; + + r = jQuery.merge( r, ret[i].getElementsByTagName( tag )); + } + + // It's faster to filter by class and be done with it + if ( m[1] == "." ) + r = jQuery.classFilter( r, m[2] ); + + // Same with ID filtering + if ( m[1] == "#" ) { + var tmp = []; + + // Try to find the element with the ID + for ( var i = 0; r[i]; i++ ) + if ( r[i].getAttribute("id") == m[2] ) { + tmp = [ r[i] ]; + break; + } + + r = tmp; + } + + ret = r; + } + + t = t.replace( re2, "" ); + } + + } + + // If a selector string still exists + if ( t ) { + // Attempt to filter it + var val = jQuery.filter(t,r); + ret = r = val.r; + t = jQuery.trim(val.t); + } + } + + // An error occurred with the selector; + // just return an empty set instead + if ( t ) + ret = []; + + // Remove the root context + if ( ret && context == ret[0] ) + ret.shift(); + + // And combine the results + done = jQuery.merge( done, ret ); + + return done; + }, + + classFilter: function(r,m,not){ + m = " " + m + " "; + var tmp = []; + for ( var i = 0; r[i]; i++ ) { + var pass = (" " + r[i].className + " ").indexOf( m ) >= 0; + if ( !not && pass || not && !pass ) + tmp.push( r[i] ); + } + return tmp; + }, + + filter: function(t,r,not) { + var last; + + // Look for common filter expressions + while ( t && t != last ) { + last = t; + + var p = jQuery.parse, m; + + for ( var i = 0; p[i]; i++ ) { + m = p[i].exec( t ); + + if ( m ) { + // Remove what we just matched + t = t.substring( m[0].length ); + + m[2] = m[2].replace(/\\/g, ""); + break; + } + } + + if ( !m ) + break; + + // :not() is a special case that can be optimized by + // keeping it out of the expression list + if ( m[1] == ":" && m[2] == "not" ) + r = jQuery.filter(m[3], r, true).r; + + // We can get a big speed boost by filtering by class here + else if ( m[1] == "." ) + r = jQuery.classFilter(r, m[2], not); + + else if ( m[1] == "[" ) { + var tmp = [], type = m[3]; + + for ( var i = 0, rl = r.length; i < rl; i++ ) { + var a = r[i], z = a[ jQuery.props[m[2]] || m[2] ]; + + if ( z == null || /href|src|selected/.test(m[2]) ) + z = jQuery.attr(a,m[2]) || ''; + + if ( (type == "" && !!z || + type == "=" && z == m[5] || + type == "!=" && z != m[5] || + type == "^=" && z && !z.indexOf(m[5]) || + type == "$=" && z.substr(z.length - m[5].length) == m[5] || + (type == "*=" || type == "~=") && z.indexOf(m[5]) >= 0) ^ not ) + tmp.push( a ); + } + + r = tmp; + + // We can get a speed boost by handling nth-child here + } else if ( m[1] == ":" && m[2] == "nth-child" ) { + var merge = {}, tmp = [], + test = /(\d*)n\+?(\d*)/.exec( + m[3] == "even" && "2n" || m[3] == "odd" && "2n+1" || + !/\D/.test(m[3]) && "n+" + m[3] || m[3]), + first = (test[1] || 1) - 0, last = test[2] - 0; + + for ( var i = 0, rl = r.length; i < rl; i++ ) { + var node = r[i], parentNode = node.parentNode, id = jQuery.data(parentNode); + + if ( !merge[id] ) { + var c = 1; + + for ( var n = parentNode.firstChild; n; n = n.nextSibling ) + if ( n.nodeType == 1 ) + n.nodeIndex = c++; + + merge[id] = true; + } + + var add = false; + + if ( first == 1 ) { + if ( last == 0 || node.nodeIndex == last ) + add = true; + } else if ( (node.nodeIndex + last) % first == 0 ) + add = true; + + if ( add ^ not ) + tmp.push( node ); + } + + r = tmp; + + // Otherwise, find the expression to execute + } else { + var f = jQuery.expr[m[1]]; + if ( typeof f != "string" ) + f = jQuery.expr[m[1]][m[2]]; + + // Build a custom macro to enclose it + f = eval("false||function(a,i){return " + f + "}"); + + // Execute it against the current filter + r = jQuery.grep( r, f, not ); + } + } + + // Return an array of filtered elements (r) + // and the modified expression string (t) + return { r: r, t: t }; + }, + + dir: function( elem, dir ){ + var matched = []; + var cur = elem[dir]; + while ( cur && cur != document ) { + if ( cur.nodeType == 1 ) + matched.push( cur ); + cur = cur[dir]; + } + return matched; + }, + + nth: function(cur,result,dir,elem){ + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) + if ( cur.nodeType == 1 && ++num == result ) + break; + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType == 1 && (!elem || n != elem) ) + r.push( n ); + } + + return r; + } +}); +/* + * A number of helper functions used for managing events. + * Many of the ideas behind this code orignated from + * Dean Edwards' addEvent library. + */ +jQuery.event = { + + // Bind an event to an element + // Original by Dean Edwards + 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; + + // Make sure that the function being executed has a unique ID + if ( !handler.guid ) + handler.guid = this.guid++; + + // if data is passed, bind to handler + if( data != undefined ) { + // Create temporary function pointer to original handler + var fn = handler; + + // Create unique handler function, wrapped around original handler + handler = function() { + // Pass arguments and context to original handler + return fn.apply(this, arguments); + }; + + // Store data in unique handler + handler.data = data; + + // Set the guid of unique handler to the same of original handler, so it can be removed + handler.guid = fn.guid; + } + + // Namespaced event handlers + var parts = type.split("."); + type = parts[0]; + handler.type = parts[1]; + + // Init the element's event structure + var events = jQuery.data(element, "events") || jQuery.data(element, "events", {}); + + var handle = jQuery.data(element, "handle") || jQuery.data(element, "handle", function(){ + // returned undefined or false + var val; + + // Handle the second event of a trigger and when + // an event is called after a page has unloaded + if ( typeof jQuery == "undefined" || jQuery.event.triggered ) + return val; + + val = jQuery.event.handle.apply(element, arguments); + + return val; + }); + + // Get the current list of functions bound to this event + var handlers = events[type]; + + // Init the event handler queue + if (!handlers) { + handlers = events[type] = {}; + + // And bind the global event handler to the element + if (element.addEventListener) + element.addEventListener(type, handle, false); + else + element.attachEvent("on" + type, handle); + } + + // Add the function to the element's handler list + handlers[handler.guid] = handler; + + // Keep track of which events have been used, for global triggering + this.global[type] = true; + }, + + guid: 1, + global: {}, + + // Detach an event or set of events from an element + remove: function(element, type, handler) { + var events = jQuery.data(element, "events"), ret, index; + + // Namespaced event handlers + if ( typeof type == "string" ) { + var parts = type.split("."); + type = parts[0]; + } + + if ( events ) { + // type is actually an event object here + if ( type && type.type ) { + handler = type.handler; + type = type.type; + } + + if ( !type ) { + for ( type in events ) + this.remove( element, type ); + + } else if ( events[type] ) { + // remove the given handler for the given type + if ( handler ) + delete events[type][handler.guid]; + + // remove all handlers for the given type + else + for ( handler in events[type] ) + // Handle the removal of namespaced events + if ( !parts[1] || events[type][handler].type == parts[1] ) + delete events[type][handler]; + + // remove generic event handler if no more handlers exist + for ( ret in events[type] ) break; + if ( !ret ) { + if (element.removeEventListener) + element.removeEventListener(type, jQuery.data(element, "handle"), false); + else + element.detachEvent("on" + type, jQuery.data(element, "handle")); + ret = null; + delete events[type]; + } + } + + // Remove the expando if it's no longer used + for ( ret in events ) break; + if ( !ret ) { + jQuery.removeData( element, "events" ); + jQuery.removeData( element, "handle" ); + } + } + }, + + trigger: function(type, data, element, donative, extra) { + // Clone the incoming data, if any + data = jQuery.makeArray(data || []); + + // Handle a global trigger + if ( !element ) { + // Only trigger if we've ever bound an event for it + if ( this.global[type] ) + jQuery("*").add([window, document]).trigger(type, data); + + // Handle triggering a single element + } else { + var val, ret, fn = jQuery.isFunction( element[ type ] || null ), + // Check to see if we need to provide a fake event, or not + event = !data[0] || !data[0].preventDefault; + + // Pass along a fake event + if ( event ) + data.unshift( this.fix({ type: type, target: element }) ); + + // Enforce the right trigger type + data[0].type = type; + + // Trigger the event + if ( jQuery.isFunction( jQuery.data(element, "handle") ) ) + val = jQuery.data(element, "handle").apply( element, data ); + + // Handle triggering native .onfoo handlers + if ( !fn && element["on"+type] && element["on"+type].apply( element, data ) === false ) + val = false; + + // Extra functions don't get the custom event object + if ( event ) + data.shift(); + + // Handle triggering of extra function + if ( extra && extra.apply( element, data ) === false ) + val = false; + + // Trigger the native events (except for clicks on links) + if ( fn && donative !== false && val !== false && !(jQuery.nodeName(element, 'a') && type == "click") ) { + this.triggered = true; + element[ type ](); + } + + this.triggered = false; + } + + return val; + }, + + handle: function(event) { + // returned undefined or false + var val; + + // Empty object is for triggered events with no data + event = jQuery.event.fix( event || window.event || {} ); + + // Namespaced event handlers + var parts = event.type.split("."); + event.type = parts[0]; + + var handlers = jQuery.data(this, "events") && jQuery.data(this, "events")[event.type], args = Array.prototype.slice.call( arguments, 1 ); + args.unshift( event ); + + for ( var j in handlers ) { + var handler = handlers[j]; + // Pass in a reference to the handler function itself + // So that we can later remove it + args[0].handler = handler; + args[0].data = handler.data; + + // Filter the functions by class + if ( !parts[1] || handler.type == parts[1] ) { + var ret = handler.apply( this, args ); + + if ( val !== false ) + val = ret; + + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + + // Clean up added properties in IE to prevent memory leak + if (jQuery.browser.msie) + event.target = event.preventDefault = event.stopPropagation = + event.handler = event.data = null; + + return val; + }, + + fix: function(event) { + // store a copy of the original event object + // and clone to set read-only properties + var originalEvent = event; + event = jQuery.extend({}, originalEvent); + + // add preventDefault and stopPropagation since + // they will not work on the clone + event.preventDefault = function() { + // if preventDefault exists run it on the original event + if (originalEvent.preventDefault) + originalEvent.preventDefault(); + // otherwise set the returnValue property of the original event to false (IE) + originalEvent.returnValue = false; + }; + event.stopPropagation = function() { + // if stopPropagation exists run it on the original event + if (originalEvent.stopPropagation) + originalEvent.stopPropagation(); + // otherwise set the cancelBubble property of the original event to true (IE) + originalEvent.cancelBubble = true; + }; + + // Fix target property, if necessary + if ( !event.target && event.srcElement ) + event.target = event.srcElement; + + // check if target is a textnode (safari) + if (jQuery.browser.safari && event.target.nodeType == 3) + event.target = originalEvent.target.parentNode; + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && event.fromElement ) + event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && event.clientX != null ) { + var doc = document.documentElement, body = document.body; + event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0); + event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientLeft || 0); + } + + // Add which for key events + if ( !event.which && (event.charCode || event.keyCode) ) + event.which = event.charCode || event.keyCode; + + // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) + if ( !event.metaKey && event.ctrlKey ) + event.metaKey = event.ctrlKey; + + // Add which for click: 1 == left; 2 == middle; 3 == right + // Note: button is not normalized, so don't use it + if ( !event.which && event.button ) + event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); + + return event; + } +}; + +jQuery.fn.extend({ + bind: function( type, data, fn ) { + return type == "unload" ? this.one(type, data, fn) : this.each(function(){ + jQuery.event.add( this, type, fn || data, fn && data ); + }); + }, + + one: function( type, data, fn ) { + return this.each(function(){ + jQuery.event.add( this, type, function(event) { + jQuery(this).unbind(event); + return (fn || data).apply( this, arguments); + }, fn && data); + }); + }, + + unbind: function( type, fn ) { + return this.each(function(){ + jQuery.event.remove( this, type, fn ); + }); + }, + + trigger: function( type, data, fn ) { + return this.each(function(){ + jQuery.event.trigger( type, data, this, true, fn ); + }); + }, + + triggerHandler: function( type, data, fn ) { + if ( this[0] ) + return jQuery.event.trigger( type, data, this[0], false, fn ); + }, + + toggle: function() { + // Save reference to arguments for access in closure + var args = arguments; + + return this.click(function(event) { + // Figure out which function to execute + this.lastToggle = 0 == this.lastToggle ? 1 : 0; + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[this.lastToggle].apply( this, [event] ) || false; + }); + }, + + hover: function(fnOver, fnOut) { + + // A private function for handling mouse 'hovering' + function handleHover(event) { + // Check if mouse(over|out) are still within the same parent element + var parent = event.relatedTarget; + + // Traverse up the tree + while ( parent && parent != this ) try { parent = parent.parentNode; } catch(error) { parent = this; }; + + // If we actually just moused on to a sub-element, ignore it + if ( parent == this ) return false; + + // Execute the right function + return (event.type == "mouseover" ? fnOver : fnOut).apply(this, [event]); + } + + // Bind the function to the two event listeners + return this.mouseover(handleHover).mouseout(handleHover); + }, + + ready: function(fn) { + // Attach the listeners + bindReady(); + + // If the DOM is already ready + if ( jQuery.isReady ) + // Execute the function immediately + fn.apply( document, [jQuery] ); + + // Otherwise, remember the function for later + else + // Add the function to the wait list + jQuery.readyList.push( function() { return fn.apply(this, [jQuery]); } ); + + return this; + } +}); + +jQuery.extend({ + /* + * All the code that makes DOM Ready work nicely. + */ + isReady: false, + readyList: [], + + // Handle when the DOM is ready + ready: function() { + // Make sure that the DOM is not already loaded + if ( !jQuery.isReady ) { + // Remember that the DOM is ready + jQuery.isReady = true; + + // If there are functions bound, to execute + if ( jQuery.readyList ) { + // Execute all of them + jQuery.each( jQuery.readyList, function(){ + this.apply( document ); + }); + + // Reset the list of functions + jQuery.readyList = null; + } + // Remove event listener to avoid memory leak + if ( jQuery.browser.mozilla || jQuery.browser.opera ) + document.removeEventListener( "DOMContentLoaded", jQuery.ready, false ); + } + } +}); + + +jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," + + "mousedown,mouseup,mousemove,mouseover,mouseout,change,select," + + "submit,keydown,keypress,keyup,error").split(","), function(i, name){ + + // Handle event binding + jQuery.fn[name] = function(fn){ + return fn ? this.bind(name, fn) : this.trigger(name); + }; +}); + +var readyBound = false; + +function bindReady(){ + if ( readyBound ) return; + readyBound = true; + + // If Mozilla is used + if ( jQuery.browser.mozilla || jQuery.browser.opera ) + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", jQuery.ready, false ); + + // If Safari or IE is used + // Continually check to see if the document is ready + else (function(){ + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + if ( jQuery.browser.msie || document.readyState != "loaded" && document.readyState != "complete" ) + document.documentElement.doScroll("left"); + } catch( error ) { + return setTimeout( arguments.callee, 0 ); + } + + // and execute any waiting functions + jQuery.ready(); + })(); + + // A fallback to window.onload, that will always work + jQuery.event.add( window, "load", jQuery.ready ); +} + +// Prevent memory leaks in IE +if ( jQuery.browser.msie ) + jQuery(window).bind("unload", function() { + $("*").add([document, window]).unbind(); + }); +jQuery.fn.extend({ + load: function( url, params, callback ) { + if ( jQuery.isFunction( url ) ) + return this.bind("load", url); + + var off = url.indexOf(" "); + if ( off >= 0 ) { + var selector = url.slice(off, url.length); + url = url.slice(0, off); + } + + callback = callback || function(){}; + + // Default to a GET request + var type = "GET"; + + // If the second parameter was provided + if ( params ) + // If it's a function + if ( jQuery.isFunction( params ) ) { + // We assume that it's the callback + callback = params; + params = null; + + // Otherwise, build a param string + } else { + params = jQuery.param( params ); + type = "POST"; + } + + var self = this; + + // Request the remote document + jQuery.ajax({ + url: url, + type: type, + data: params, + complete: function(res, status){ + // If successful, inject the HTML into all the matched elements + if ( status == "success" || status == "notmodified" ) + // See if a selector was specified + self.html( selector ? + // Create a dummy div to hold the results + jQuery("
") + // inject the contents of the document in, removing the scripts + // to avoid any 'Permission Denied' errors in IE + .append(res.responseText.replace(//g, "")) + + // Locate the specified elements + .find(selector) : + + // If not, just inject the full result + res.responseText ); + + // Add delay to account for Safari's delay in globalEval + setTimeout(function(){ + self.each( callback, [res.responseText, status, res] ); + }, 13); + } + }); + return this; + }, + + serialize: function() { + return jQuery.param(this.serializeArray()); + }, + serializeArray: function() { + return this.map(function(){ + return jQuery.nodeName(this, "form") ? + jQuery.makeArray(this.elements) : this; + }) + .filter(function(){ + return this.name && !this.disabled && + (this.checked || /select|textarea/i.test(this.nodeName) || + /text|hidden|password/i.test(this.type)); + }) + .map(function(i, elem){ + var val = jQuery(this).val(); + return val == null ? null : + val.constructor == Array ? + jQuery.map( val, function(val, i){ + return {name: elem.name, value: val}; + }) : + {name: elem.name, value: val}; + }).get(); + } +}); + +// Attach a bunch of functions for handling common AJAX events +jQuery.each( "ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","), function(i,o){ + jQuery.fn[o] = function(f){ + return this.bind(o, f); + }; +}); + +var jsc = (new Date).getTime(); + +jQuery.extend({ + get: function( url, data, callback, type ) { + // shift arguments if data argument was ommited + if ( jQuery.isFunction( data ) ) { + callback = data; + data = null; + } + + return jQuery.ajax({ + type: "GET", + url: url, + data: data, + success: callback, + dataType: type + }); + }, + + getScript: function( url, callback ) { + return jQuery.get(url, null, callback, "script"); + }, + + getJSON: function( url, data, callback ) { + return jQuery.get(url, data, callback, "json"); + }, + + post: function( url, data, callback, type ) { + if ( jQuery.isFunction( data ) ) { + callback = data; + data = {}; + } + + return jQuery.ajax({ + type: "POST", + url: url, + data: data, + success: callback, + dataType: type + }); + }, + + ajaxSetup: function( settings ) { + jQuery.extend( jQuery.ajaxSettings, settings ); + }, + + ajaxSettings: { + global: true, + type: "GET", + timeout: 0, + contentType: "application/x-www-form-urlencoded", + processData: true, + async: true, + data: null + }, + + // Last-Modified header cache for next request + lastModified: {}, + + ajax: function( s ) { + var jsonp, jsre = /=(\?|%3F)/g, status, data; + + // Extend the settings, but re-extend 's' so that it can be + // checked again later (in the test suite, specifically) + s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s)); + + // convert data if not already a string + if ( s.data && s.processData && typeof s.data != "string" ) + s.data = jQuery.param(s.data); + + // Handle JSONP Parameter Callbacks + if ( s.dataType == "jsonp" ) { + if ( s.type.toLowerCase() == "get" ) { + if ( !s.url.match(jsre) ) + s.url += (s.url.match(/\?/) ? "&" : "?") + (s.jsonp || "callback") + "=?"; + } else if ( !s.data || !s.data.match(jsre) ) + s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?"; + s.dataType = "json"; + } + + // Build temporary JSONP function + if ( s.dataType == "json" && (s.data && jsre.test( s.data ) || s.url.match(jsre)) ) { + jsonp = "jsonp" + jsc++; + + // Replace the =? sequence both in the query string and the data + if ( s.data ) + s.data = (s.data + "").replace(jsre, "=" + jsonp); + s.url = s.url.replace(jsre, "=" + jsonp); + + // We need to make sure + // that a JSONP style response is executed properly + s.dataType = "script"; + + // Handle JSONP-style loading + window[ jsonp ] = function(tmp){ + data = tmp; + success(); + complete(); + // Garbage collect + window[ jsonp ] = undefined; + try{ delete window[ jsonp ]; } catch(e){} + }; + } + + if ( s.dataType == "script" && s.cache == null ) + s.cache = false; + + if ( s.cache === false && s.type.toLowerCase() == "get" ) + s.url += (s.url.match(/\?/) ? "&" : "?") + "_=" + (new Date()).getTime(); + + // If data is available, append data to url for get requests + if ( s.data && s.type.toLowerCase() == "get" ) { + s.url += (s.url.match(/\?/) ? "&" : "?") + s.data; + + // IE likes to send both get and post data, prevent this + s.data = null; + } + + // Watch for a new set of requests + if ( s.global && ! jQuery.active++ ) + jQuery.event.trigger( "ajaxStart" ); + + // If we're requesting a remote document + // and trying to load JSON or Script + if ( !s.url.indexOf("http") && s.dataType == "script" ) { + var head = document.getElementsByTagName("head")[0]; + var script = document.createElement("script"); + script.src = s.url; + + // Handle Script loading + if ( !jsonp ) { + var done = false; + + // Attach handlers for all browsers + script.onload = script.onreadystatechange = function(){ + if ( !done && (!this.readyState || + this.readyState == "loaded" || this.readyState == "complete") ) { + done = true; + success(); + complete(); + head.removeChild( script ); + } + }; + } + + head.appendChild(script); + + // We handle everything using the script element injection + return; + } + + var requestDone = false; + + // Create the request object; Microsoft failed to properly + // implement the XMLHttpRequest in IE7, so we use the ActiveXObject when it is available + var xml = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest(); + + // Open the socket + xml.open(s.type, s.url, s.async); + + // Set the correct header, if data is being sent + if ( s.data ) + xml.setRequestHeader("Content-Type", s.contentType); + + // Set the If-Modified-Since header, if ifModified mode. + if ( s.ifModified ) + xml.setRequestHeader("If-Modified-Since", + jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" ); + + // Set header so the called script knows that it's an XMLHttpRequest + xml.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + + // Allow custom headers/mimetypes + if ( s.beforeSend ) + s.beforeSend(xml); + + if ( s.global ) + jQuery.event.trigger("ajaxSend", [xml, s]); + + // Wait for a response to come back + var onreadystatechange = function(isTimeout){ + // The transfer is complete and the data is available, or the request timed out + if ( !requestDone && xml && (xml.readyState == 4 || isTimeout == "timeout") ) { + requestDone = true; + + // clear poll interval + if (ival) { + clearInterval(ival); + ival = null; + } + + status = isTimeout == "timeout" && "timeout" || + !jQuery.httpSuccess( xml ) && "error" || + s.ifModified && jQuery.httpNotModified( xml, s.url ) && "notmodified" || + "success"; + + if ( status == "success" ) { + // Watch for, and catch, XML document parse errors + try { + // process the data (runs the xml through httpData regardless of callback) + data = jQuery.httpData( xml, s.dataType ); + } catch(e) { + status = "parsererror"; + } + } + + // Make sure that the request was successful or notmodified + if ( status == "success" ) { + // Cache Last-Modified header, if ifModified mode. + var modRes; + try { + modRes = xml.getResponseHeader("Last-Modified"); + } catch(e) {} // swallow exception thrown by FF if header is not available + + if ( s.ifModified && modRes ) + jQuery.lastModified[s.url] = modRes; + + // JSONP handles its own success callback + if ( !jsonp ) + success(); + } else + jQuery.handleError(s, xml, status); + + // Fire the complete handlers + complete(); + + // Stop memory leaks + if ( s.async ) + xml = null; + } + }; + + if ( s.async ) { + // don't attach the handler to the request, just poll it instead + var ival = setInterval(onreadystatechange, 13); + + // Timeout checker + if ( s.timeout > 0 ) + setTimeout(function(){ + // Check to see if the request is still happening + if ( xml ) { + // Cancel the request + xml.abort(); + + if( !requestDone ) + onreadystatechange( "timeout" ); + } + }, s.timeout); + } + + // Send the data + try { + xml.send(s.data); + } catch(e) { + jQuery.handleError(s, xml, null, e); + } + + // firefox 1.5 doesn't fire statechange for sync requests + if ( !s.async ) + onreadystatechange(); + + // return XMLHttpRequest to allow aborting the request etc. + return xml; + + function success(){ + // If a local callback was specified, fire it and pass it the data + if ( s.success ) + s.success( data, status ); + + // Fire the global callback + if ( s.global ) + jQuery.event.trigger( "ajaxSuccess", [xml, s] ); + } + + function complete(){ + // Process result + if ( s.complete ) + s.complete(xml, status); + + // The request was completed + if ( s.global ) + jQuery.event.trigger( "ajaxComplete", [xml, s] ); + + // Handle the global AJAX counter + if ( s.global && ! --jQuery.active ) + jQuery.event.trigger( "ajaxStop" ); + } + }, + + handleError: function( s, xml, status, e ) { + // If a local callback was specified, fire it + if ( s.error ) s.error( xml, status, e ); + + // Fire the global callback + if ( s.global ) + jQuery.event.trigger( "ajaxError", [xml, s, e] ); + }, + + // Counter for holding the number of active queries + active: 0, + + // Determines if an XMLHttpRequest was successful or not + httpSuccess: function( r ) { + try { + return !r.status && location.protocol == "file:" || + ( r.status >= 200 && r.status < 300 ) || r.status == 304 || + jQuery.browser.safari && r.status == undefined; + } catch(e){} + return false; + }, + + // Determines if an XMLHttpRequest returns NotModified + httpNotModified: function( xml, url ) { + try { + var xmlRes = xml.getResponseHeader("Last-Modified"); + + // Firefox always returns 200. check Last-Modified date + return xml.status == 304 || xmlRes == jQuery.lastModified[url] || + jQuery.browser.safari && xml.status == undefined; + } catch(e){} + return false; + }, + + httpData: function( r, type ) { + var ct = r.getResponseHeader("content-type"); + var xml = type == "xml" || !type && ct && ct.indexOf("xml") >= 0; + var data = xml ? r.responseXML : r.responseText; + + if ( xml && data.documentElement.tagName == "parsererror" ) + throw "parsererror"; + + // If the type is "script", eval it in global context + if ( type == "script" ) + jQuery.globalEval( data ); + + // Get the JavaScript object, if JSON is used. + if ( type == "json" ) + data = eval("(" + data + ")"); + + return data; + }, + + // Serialize an array of form elements or a set of + // key/values into a query string + param: function( a ) { + var s = []; + + // If an array was passed in, assume that it is an array + // of form elements + if ( a.constructor == Array || a.jquery ) + // Serialize the form elements + jQuery.each( a, function(){ + s.push( encodeURIComponent(this.name) + "=" + encodeURIComponent( this.value ) ); + }); + + // Otherwise, assume that it's an object of key/value pairs + else + // Serialize the key/values + for ( var j in a ) + // If the value is an array then the key names need to be repeated + if ( a[j] && a[j].constructor == Array ) + jQuery.each( a[j], function(){ + s.push( encodeURIComponent(j) + "=" + encodeURIComponent( this ) ); + }); + else + s.push( encodeURIComponent(j) + "=" + encodeURIComponent( a[j] ) ); + + // Return the resulting serialization + return s.join("&").replace(/%20/g, "+"); + } + +}); +jQuery.fn.extend({ + show: function(speed,callback){ + return speed ? + this.animate({ + height: "show", width: "show", opacity: "show" + }, speed, callback) : + + this.filter(":hidden").each(function(){ + this.style.display = this.oldblock ? this.oldblock : ""; + if ( jQuery.css(this,"display") == "none" ) + this.style.display = "block"; + }).end(); + }, + + hide: function(speed,callback){ + return speed ? + this.animate({ + height: "hide", width: "hide", opacity: "hide" + }, speed, callback) : + + this.filter(":visible").each(function(){ + this.oldblock = this.oldblock || jQuery.css(this,"display"); + if ( this.oldblock == "none" ) + this.oldblock = "block"; + this.style.display = "none"; + }).end(); + }, + + // Save the old toggle function + _toggle: jQuery.fn.toggle, + + toggle: function( fn, fn2 ){ + return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ? + this._toggle( fn, fn2 ) : + fn ? + this.animate({ + height: "toggle", width: "toggle", opacity: "toggle" + }, fn, fn2) : + this.each(function(){ + jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ](); + }); + }, + + slideDown: function(speed,callback){ + return this.animate({height: "show"}, speed, callback); + }, + + slideUp: function(speed,callback){ + return this.animate({height: "hide"}, speed, callback); + }, + + slideToggle: function(speed, callback){ + return this.animate({height: "toggle"}, speed, callback); + }, + + fadeIn: function(speed, callback){ + return this.animate({opacity: "show"}, speed, callback); + }, + + fadeOut: function(speed, callback){ + return this.animate({opacity: "hide"}, speed, callback); + }, + + fadeTo: function(speed,to,callback){ + return this.animate({opacity: to}, speed, callback); + }, + + animate: function( prop, speed, easing, callback ) { + var optall = jQuery.speed(speed, easing, callback); + + return this[ optall.queue === false ? "each" : "queue" ](function(){ + var opt = jQuery.extend({}, optall); + var hidden = jQuery(this).is(":hidden"), self = this; + + for ( var p in prop ) { + if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden ) + return jQuery.isFunction(opt.complete) && opt.complete.apply(this); + + if ( p == "height" || p == "width" ) { + // Store display property + opt.display = jQuery.css(this, "display"); + + // Make sure that nothing sneaks out + opt.overflow = this.style.overflow; + } + } + + if ( opt.overflow != null ) + this.style.overflow = "hidden"; + + opt.curAnim = jQuery.extend({}, prop); + + jQuery.each( prop, function(name, val){ + var e = new jQuery.fx( self, opt, name ); + + if ( /toggle|show|hide/.test(val) ) + e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop ); + else { + var parts = val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/), + start = e.cur(true) || 0; + + if ( parts ) { + var end = parseFloat(parts[2]), + unit = parts[3] || "px"; + + // We need to compute starting value + if ( unit != "px" ) { + self.style[ name ] = (end || 1) + unit; + start = ((end || 1) / e.cur(true)) * start; + self.style[ name ] = start + unit; + } + + // If a +=/-= token was provided, we're doing a relative animation + if ( parts[1] ) + end = ((parts[1] == "-=" ? -1 : 1) * end) + start; + + e.custom( start, end, unit ); + } else + e.custom( start, val, "" ); + } + }); + + // For JS strict compliance + return true; + }); + }, + + queue: function(type, fn){ + if ( jQuery.isFunction(type) ) { + fn = type; + type = "fx"; + } + + if ( !type || (typeof type == "string" && !fn) ) + return queue( this[0], type ); + + return this.each(function(){ + if ( fn.constructor == Array ) + queue(this, type, fn); + else { + queue(this, type).push( fn ); + + if ( queue(this, type).length == 1 ) + fn.apply(this); + } + }); + }, + + stop: function(){ + var timers = jQuery.timers; + + return this.each(function(){ + for ( var i = 0; i < timers.length; i++ ) + if ( timers[i].elem == this ) + timers.splice(i--, 1); + }).dequeue(); + } + +}); + +var queue = function( elem, type, array ) { + if ( !elem ) + return; + + var q = jQuery.data( elem, type + "queue" ); + + if ( !q || array ) + q = jQuery.data( elem, type + "queue", + array ? jQuery.makeArray(array) : [] ); + + return q; +}; + +jQuery.fn.dequeue = function(type){ + type = type || "fx"; + + return this.each(function(){ + var q = queue(this, type); + + q.shift(); + + if ( q.length ) + q[0].apply( this ); + }); +}; + +jQuery.extend({ + + speed: function(speed, easing, fn) { + var opt = speed && speed.constructor == Object ? speed : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && easing.constructor != Function && easing + }; + + opt.duration = (opt.duration && opt.duration.constructor == Number ? + opt.duration : + { slow: 600, fast: 200 }[opt.duration]) || 400; + + // Queueing + opt.old = opt.complete; + opt.complete = function(){ + jQuery(this).dequeue(); + if ( jQuery.isFunction( opt.old ) ) + opt.old.apply( this ); + }; + + return opt; + }, + + easing: { + linear: function( p, n, firstNum, diff ) { + return firstNum + diff * p; + }, + swing: function( p, n, firstNum, diff ) { + return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum; + } + }, + + timers: [], + + fx: function( elem, options, prop ){ + this.options = options; + this.elem = elem; + this.prop = prop; + + if ( !options.orig ) + options.orig = {}; + } + +}); + +jQuery.fx.prototype = { + + // Simple function for setting a style value + update: function(){ + if ( this.options.step ) + this.options.step.apply( this.elem, [ this.now, this ] ); + + (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this ); + + // Set display property to block for height/width animations + if ( this.prop == "height" || this.prop == "width" ) + this.elem.style.display = "block"; + }, + + // Get the current size + cur: function(force){ + if ( this.elem[this.prop] != null && this.elem.style[this.prop] == null ) + return this.elem[ this.prop ]; + + var r = parseFloat(jQuery.curCSS(this.elem, this.prop, force)); + return r && r > -10000 ? r : parseFloat(jQuery.css(this.elem, this.prop)) || 0; + }, + + // Start an animation from one number to another + custom: function(from, to, unit){ + this.startTime = (new Date()).getTime(); + this.start = from; + this.end = to; + this.unit = unit || this.unit || "px"; + this.now = this.start; + this.pos = this.state = 0; + this.update(); + + var self = this; + function t(){ + return self.step(); + } + + t.elem = this.elem; + + jQuery.timers.push(t); + + if ( jQuery.timers.length == 1 ) { + var timer = setInterval(function(){ + var timers = jQuery.timers; + + for ( var i = 0; i < timers.length; i++ ) + if ( !timers[i]() ) + timers.splice(i--, 1); + + if ( !timers.length ) + clearInterval( timer ); + }, 13); + } + }, + + // Simple 'show' function + show: function(){ + // Remember where we started, so that we can go back to it later + this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop ); + this.options.show = true; + + // Begin the animation + this.custom(0, this.cur()); + + // Make sure that we start at a small width/height to avoid any + // flash of content + if ( this.prop == "width" || this.prop == "height" ) + this.elem.style[this.prop] = "1px"; + + // Start by showing the element + jQuery(this.elem).show(); + }, + + // Simple 'hide' function + hide: function(){ + // Remember where we started, so that we can go back to it later + this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop ); + this.options.hide = true; + + // Begin the animation + this.custom(this.cur(), 0); + }, + + // Each step of an animation + step: function(){ + var t = (new Date()).getTime(); + + if ( t > this.options.duration + this.startTime ) { + this.now = this.end; + this.pos = this.state = 1; + this.update(); + + this.options.curAnim[ this.prop ] = true; + + var done = true; + for ( var i in this.options.curAnim ) + if ( this.options.curAnim[i] !== true ) + done = false; + + if ( done ) { + if ( this.options.display != null ) { + // Reset the overflow + this.elem.style.overflow = this.options.overflow; + + // Reset the display + this.elem.style.display = this.options.display; + if ( jQuery.css(this.elem, "display") == "none" ) + this.elem.style.display = "block"; + } + + // Hide the element if the "hide" operation was done + if ( this.options.hide ) + this.elem.style.display = "none"; + + // Reset the properties, if the item has been hidden or shown + if ( this.options.hide || this.options.show ) + for ( var p in this.options.curAnim ) + jQuery.attr(this.elem.style, p, this.options.orig[p]); + } + + // If a callback was provided, execute it + if ( done && jQuery.isFunction( this.options.complete ) ) + // Execute the complete function + this.options.complete.apply( this.elem ); + + return false; + } else { + var n = t - this.startTime; + this.state = n / this.options.duration; + + // Perform the easing function, defaults to swing + this.pos = jQuery.easing[this.options.easing || (jQuery.easing.swing ? "swing" : "linear")](this.state, n, 0, 1, this.options.duration); + this.now = this.start + ((this.end - this.start) * this.pos); + + // Perform the next step of the animation + this.update(); + } + + return true; + } + +}; + +jQuery.fx.step = { + scrollLeft: function(fx){ + fx.elem.scrollLeft = fx.now; + }, + + scrollTop: function(fx){ + fx.elem.scrollTop = fx.now; + }, + + opacity: function(fx){ + jQuery.attr(fx.elem.style, "opacity", fx.now); + }, + + _default: function(fx){ + fx.elem.style[ fx.prop ] = fx.now + fx.unit; + } +}; +// The Offset Method +// Originally By Brandon Aaron, part of the Dimension Plugin +// http://jquery.com/plugins/project/dimensions +jQuery.fn.offset = function() { + var left = 0, top = 0, elem = this[0], results; + + if ( elem ) with ( jQuery.browser ) { + var parent = elem.parentNode, + offsetChild = elem, + offsetParent = elem.offsetParent, + doc = elem.ownerDocument, + safari2 = safari && parseInt(version) < 522, + fixed = jQuery.css(elem, "position") == "fixed"; + + // Use getBoundingClientRect if available + if ( elem.getBoundingClientRect ) { + var box = elem.getBoundingClientRect(); + + // Add the document scroll offsets + add( + box.left + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft), + box.top + Math.max(doc.documentElement.scrollTop, doc.body.scrollTop) + ); + + // IE adds the HTML element's border, by default it is medium which is 2px + // IE 6 and IE 7 quirks mode the border width is overwritable by the following css html { border: 0; } + // IE 7 standards mode, the border is always 2px + if ( msie ) { + var border = jQuery("html").css("borderWidth"); + border = (border == "medium" || jQuery.boxModel && parseInt(version) >= 7) && 2 || border; + add( -border, -border ); + } + + // Otherwise loop through the offsetParents and parentNodes + } else { + + // Initial element offsets + add( elem.offsetLeft, elem.offsetTop ); + + // Get parent offsets + while ( offsetParent ) { + // Add offsetParent offsets + add( offsetParent.offsetLeft, offsetParent.offsetTop ); + + // Mozilla and Safari > 2 does not include the border on offset parents + // However Mozilla adds the border for table or table cells + if ( mozilla && !/^t(able|d|h)$/i.test(offsetParent.tagName) || safari && !safari2 ) + border( offsetParent ); + + // Add the document scroll offsets if position is fixed on any offsetParent + if ( !fixed && jQuery.css(offsetParent, "position") == "fixed" ) + fixed = true; + + // Set offsetChild to previous offsetParent unless it is the body element + offsetChild = /^body$/i.test(offsetParent.tagName) ? offsetChild : offsetParent; + // Get next offsetParent + offsetParent = offsetParent.offsetParent; + } + + // Get parent scroll offsets + while ( parent.tagName && !/^body|html$/i.test(parent.tagName) ) { + // Remove parent scroll UNLESS that parent is inline or a table-row to work around Opera inline/table scrollLeft/Top bug + if ( !/^inline|table-row.*$/i.test(jQuery.css(parent, "display")) ) + // Subtract parent scroll offsets + add( -parent.scrollLeft, -parent.scrollTop ); + + // Mozilla does not add the border for a parent that has overflow != visible + if ( mozilla && jQuery.css(parent, "overflow") != "visible" ) + border( parent ); + + // Get next parent + parent = parent.parentNode; + } + + // Safari <= 2 doubles body offsets with a fixed position element/offsetParent or absolutely positioned offsetChild + // Mozilla doubles body offsets with a non-absolutely positioned offsetChild + if ( (safari2 && (fixed || jQuery.css(offsetChild, "position") == "absolute")) || + (mozilla && jQuery.css(offsetChild, "position") != "absoltue") ) + add( -doc.body.offsetLeft, -doc.body.offsetTop ); + + // Add the document scroll offsets if position is fixed + if ( fixed ) + add( + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft), + Math.max(doc.documentElement.scrollTop, doc.body.scrollTop) + ); + } + + // Return an object with top and left properties + results = { top: top, left: left }; + } + + return results; + + function border(elem) { + add( jQuery.css(elem, "borderLeftWidth"), jQuery.css(elem, "borderTopWidth") ); + } + + function add(l, t) { + left += parseInt(l) || 0; + top += parseInt(t) || 0; + } +}; +})();