diff options
author | pete <pete@36083f99-b078-4883-b0ff-0f9b5a30f544> | 2008-05-09 00:31:16 +0000 |
---|---|---|
committer | pete <pete@36083f99-b078-4883-b0ff-0f9b5a30f544> | 2008-05-09 00:31:16 +0000 |
commit | e2a2e2b28bfc2b70ade8c6fb52363176af12804b (patch) | |
tree | ea5bbc78593c434817c57b0336bff772399fd535 /vendors/jquery | |
parent | ee3f793908dd34b3aa9e6e96ba5c53b4b1500732 (diff) | |
download | elgg-e2a2e2b28bfc2b70ade8c6fb52363176af12804b.tar.gz elgg-e2a2e2b28bfc2b70ade8c6fb52363176af12804b.tar.bz2 |
jquery framework
git-svn-id: https://code.elgg.org/elgg/trunk@638 36083f99-b078-4883-b0ff-0f9b5a30f544
Diffstat (limited to 'vendors/jquery')
-rwxr-xr-x | vendors/jquery/init.js | 131 | ||||
-rwxr-xr-x | vendors/jquery/jquery-1.2.4a.js | 3436 | ||||
-rwxr-xr-x | vendors/jquery/ui.base.js | 204 | ||||
-rwxr-xr-x | vendors/jquery/ui.draggable.js | 572 | ||||
-rwxr-xr-x | vendors/jquery/ui.droppable.js | 312 | ||||
-rwxr-xr-x | vendors/jquery/ui.sortable.js | 676 |
6 files changed, 5331 insertions, 0 deletions
diff --git a/vendors/jquery/init.js b/vendors/jquery/init.js new file mode 100755 index 000000000..b60d268f0 --- /dev/null +++ b/vendors/jquery/init.js @@ -0,0 +1,131 @@ +(function($){ + var updateUpDown = function(sortable){ + $('div:not(.ui-sortable-helper)', sortable) + .removeClass('first').removeClass('last') + .find('.up, .down').removeClass('disabled').end() + .filter(':first').addClass('first').find('.up').addClass('disabled').end().end() + .filter(':last').addClass('last').find('.down').addClass('disabled').end().end(); + }; + + var moveUpDown = function(){ + var link = $(this), + dl = link.parents('div'), + prev = dl.prev('div'), + next = dl.next('div'); + + if(link.is('.up') && prev.length > 0) + dl.insertBefore(prev); + + if(link.is('.down') && next.length > 0) + dl.insertAfter(next); + + updateUpDown(dl.parent()); + }; + + var addItem = function(){ + var sortable = $(this).parents('.ui-sortable'); + var options = '<span class="options"><a class="up">up</a><a class="down">down</a></span>'; + var tpl = '<dl class="sort"><dt>{name}' + options + '</dt><dd>{desc}</dd></dl>'; + var html = tpl.replace(/{name}/g, 'Dynamic name :D').replace(/{desc}/g, 'Description'); + + sortable.append(html).sortable('refresh').find('a.up, a.down').bind('click', moveUpDown); + updateUpDown(sortable); + }; + + //var emptyTrashCan = function(item){ + // item.remove(); + //}; + + var sortableChange = function(e, ui){ + if(ui.sender){ + var w = ui.element.width(); + ui.placeholder.width(w); + ui.helper.css("width",ui.element.children().width()); + } + }; + + var sortableUpdate = function(e, ui){ + //if(ui.element[0].id == 'trashcan'){ + // emptyTrashCan(ui.item); + //} else { + updateUpDown(ui.element[0]); + if(ui.sender) + updateUpDown(ui.sender[0]); + //} + }; + + // toggle content panel + var togglePanel = function(e) { + var targetContent = $('div.panelcontent', this.parentNode.parentNode); + if (targetContent.css('display') == 'none') { + targetContent.slideDown(400); + $(this).html('[-]'); + $(this).css("color","#cccccc"); + } else { + targetContent.slideUp(400); + $(this).html('[+]'); + $(this).css("color","#666666"); + } + return false; + }; + + // toggle edit panel + var editpanel = function(e) { + var targetEditPanel = $('div.editpanel', this.parentNode.parentNode); + if (targetEditPanel.css('display') == 'none') { + targetEditPanel.slideDown(400); + } else { + targetEditPanel.slideUp(400); + } + $(this).toggleClass("active"); return false; + return false; + }; + + $(document).ready(function(){ + + // toggle edit panel + $('a.button_editpanel').bind('click', editpanel); + + // toggle content panel + $('a.togglepanel').bind('click', togglePanel); + + var els = ['#mainContent', '#sidebar_right']; + var $els = $(els.toString()); + + //$('h2', $els.slice(0,-1)).append('<span class="options"><a class="add">add</a></span>'); + //$('dt', $els).append('<span class="options"><a class="up">up</a><a class="down">down</a></span>'); + + //$('a.add').bind('click', addItem); + //$('a.up, a.down').bind('click', moveUpDown); + + //$els.each(function(){ + // updateUpDown(this); + //}); + + $els.sortable({ + items: '> div', + handle: 'h1', + cursor: 'move', + //revert: true, + cursorAt: { top: 10, left: 100 }, + //opacity: 0.8, + containment: 'parent', + appendTo: 'body', + placeholder: 'placeholder', + connectWith: els, + start: function(e,ui) { + ui.helper.css("width", ui.item.width()); + }, + change: sortableChange, + update: sortableUpdate + }); + }); + + $(window).bind('load',function(){ + setTimeout(function(){ + $('#overlay').fadeOut(function(){ + $('body').css('overflow', 'auto'); + }); + }, 450); + }); +})(jQuery);
\ No newline at end of file diff --git a/vendors/jquery/jquery-1.2.4a.js b/vendors/jquery/jquery-1.2.4a.js new file mode 100755 index 000000000..ea640733f --- /dev/null +++ b/vendors/jquery/jquery-1.2.4a.js @@ -0,0 +1,3436 @@ +(function(){ +/* + * jQuery 1.2.4a - New Wave Javascript + * + * Copyright (c) 2008 John Resig (jquery.com) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * $Date: 2008-04-08 13:40:03 -0300 (ter, 08 abr 2008) $ + * $Rev: 5214 $ + */ + +// Map over jQuery in case of overwrite +if ( window.jQuery ) + var _jQuery = window.jQuery; + +var jQuery = window.jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.prototype.init( selector, context ); +}; + +// Map over the $ in case of overwrite +if ( window.$ ) + var _$ = window.$; + +// Map the jQuery namespace to the '$' one +window.$ = jQuery; + +// A simple way to check for HTML strings or ID strings +// (both of which we optimize for) +var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/; + +// Is it a simple selector +var isSimple = /^.[^:#\[\.]*$/; + +jQuery.fn = jQuery.prototype = { + init: function( selector, context ) { + // Make sure that a selection was provided + selector = selector || document; + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this[0] = selector; + this.length = 1; + return this; + + // Handle HTML strings + } else if ( typeof selector == "string" ) { + // Are we dealing with HTML string or an ID? + var match = quickExpr.exec( selector ); + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) + selector = jQuery.clean( [ match[1] ], context ); + + // HANDLE: $("#id") + else { + var elem = document.getElementById( match[3] ); + + // Make sure an element was located + if ( elem ) + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id != match[3] ) + return jQuery().find( selector ); + + // Otherwise, we inject the element directly into the jQuery object + else { + this[0] = elem; + this.length = 1; + return this; + } + + else + selector = []; + } + + // HANDLE: $(expr, [context]) + // (which is just equivalent to: $(content).find(expr) + } else + return new jQuery( context ).find( selector ); + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) + return new jQuery( document )[ jQuery.fn.ready ? "ready" : "load" ]( selector ); + + return this.setArray( + // HANDLE: $(array) + selector.constructor == Array && selector || + + // HANDLE: $(arraylike) + // Watch for when an array-like object, contains DOM nodes, is passed in as the selector + (selector.jquery || selector.length && selector != window && !selector.nodeType && selector[0] != undefined && selector[0].nodeType) && jQuery.makeArray( selector ) || + + // HANDLE: $(*) + [ selector ] ); + }, + + // The current version of jQuery being used + jquery: "1.2.4a", + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + // The number of elements contained in the matched element set + length: 0, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == undefined ? + + // Return a 'clean' array + jQuery.makeArray( this ) : + + // Return just the object + this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + // Build a new jQuery matched element set + var ret = jQuery( elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Force the current matched set of elements to become + // the specified array of elements (destroying the stack in the process) + // You should use pushStack() in order to do this, but maintain the stack + setArray: function( elems ) { + // Resetting the length to 0, then using the native Array push + // is a super-fast way to populate an object with array-like properties + this.length = 0; + Array.prototype.push.apply( this, elems ); + + return this; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + var ret = -1; + + // Locate the position of the desired element + this.each(function(i){ + if ( this == elem ) + ret = i; + }); + + return ret; + }, + + attr: function( name, value, type ) { + var options = name; + + // Look for the case where we're accessing a style value + if ( name.constructor == String ) + if ( value == undefined ) + return this.length && jQuery[ type || "attr" ]( this[0], name ) || undefined; + + else { + options = {}; + options[ name ] = value; + } + + // Check to see if we're setting style values + return this.each(function(i){ + // Set all the styles + for ( name in options ) + jQuery.attr( + type ? + this.style : + this, + name, jQuery.prop( this, options[ name ], type, i, name ) + ); + }); + }, + + css: function( key, value ) { + // ignore negative width and height values + if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 ) + value = undefined; + return this.attr( key, value, "curCSS" ); + }, + + text: function( text ) { + if ( typeof text != "object" && text != null ) + return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) ); + + var ret = ""; + + jQuery.each( text || this, function(){ + jQuery.each( this.childNodes, function(){ + if ( this.nodeType != 8 ) + ret += this.nodeType != 1 ? + this.nodeValue : + jQuery.fn.text( [ this ] ); + }); + }); + + return ret; + }, + + wrapAll: function( html ) { + if ( this[0] ) + // The elements to wrap the target around + jQuery( html, this[0].ownerDocument ) + .clone() + .insertBefore( this[0] ) + .map(function(){ + var elem = this; + + while ( elem.firstChild ) + elem = elem.firstChild; + + return elem; + }) + .append(this); + + return this; + }, + + wrapInner: function( html ) { + return this.each(function(){ + jQuery( this ).contents().wrapAll( html ); + }); + }, + + wrap: function( html ) { + return this.each(function(){ + jQuery( this ).wrapAll( html ); + }); + }, + + append: function() { + return this.domManip(arguments, true, false, function(elem){ + if (this.nodeType == 1) + this.appendChild( elem ); + }); + }, + + prepend: function() { + return this.domManip(arguments, true, true, function(elem){ + if (this.nodeType == 1) + this.insertBefore( elem, this.firstChild ); + }); + }, + + before: function() { + return this.domManip(arguments, false, false, function(elem){ + this.parentNode.insertBefore( elem, this ); + }); + }, + + after: function() { + return this.domManip(arguments, false, true, function(elem){ + this.parentNode.insertBefore( elem, this.nextSibling ); + }); + }, + + end: function() { + return this.prevObject || jQuery( [] ); + }, + + find: function( selector ) { + var elems = jQuery.map(this, function(elem){ + return jQuery.find( selector, elem ); + }); + + return this.pushStack( /[^+>] [^+>]/.test( selector ) || selector.indexOf("..") > -1 ? + jQuery.unique( elems ) : + elems ); + }, + + clone: function( events ) { + // Do the clone + var ret = this.map(function(){ + if ( jQuery.browser.msie && !jQuery.isXMLDoc(this) ) { + // IE copies events bound via attachEvent when + // using cloneNode. Calling detachEvent on the + // clone will also remove the events from the orignal + // In order to get around this, we use innerHTML. + // Unfortunately, this means some modifications to + // attributes in IE that are actually only stored + // as properties will not be copied (such as the + // the name attribute on an input). + var clone = this.cloneNode(true), + container = document.createElement("div"); + container.appendChild(clone); + return jQuery.clean([container.innerHTML])[0]; + } else + return this.cloneNode(true); + }); + + // Need to set the expando to null on the cloned set if it exists + // removeData doesn't work here, IE removes it from the original as well + // this is primarily for IE but the data expando shouldn't be copied over in any browser + var clone = ret.find("*").andSelf().each(function(){ + if ( this[ expando ] != undefined ) + this[ expando ] = null; + }); + + // Copy the events from the original to the clone + if ( events === true ) + this.find("*").andSelf().each(function(i){ + if (this.nodeType == 3) + return; + var events = jQuery.data( this, "events" ); + + for ( var type in events ) + for ( var handler in events[ type ] ) + jQuery.event.add( clone[ i ], type, events[ type ][ handler ], events[ type ][ handler ].data ); + }); + + // Return the cloned set + return ret; + }, + + filter: function( selector ) { + return this.pushStack( + jQuery.isFunction( selector ) && + jQuery.grep(this, function(elem, i){ + return selector.call( elem, i ); + }) || + + jQuery.multiFilter( selector, this ) ); + }, + + not: function( selector ) { + if ( selector.constructor == String ) + // test special case where just one selector is passed in + if ( isSimple.test( selector ) ) + return this.pushStack( jQuery.multiFilter( selector, this, true ) ); + else + selector = jQuery.multiFilter( selector, this ); + + var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType; + return this.filter(function() { + return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector; + }); + }, + + add: function( selector ) { + return !selector ? this : this.pushStack( jQuery.merge( + this.get(), + selector.constructor == String ? + jQuery( selector ).get() : + selector.length != undefined && (!selector.nodeName || jQuery.nodeName(selector, "form")) ? + selector : [selector] ) ); + }, + + is: function( selector ) { + return selector ? + jQuery.multiFilter( selector, this ).length > 0 : + false; + }, + + hasClass: function( selector ) { + return this.is( "." + selector ); + }, + + val: function( value ) { + if ( value == undefined ) { + + if ( this.length ) { + var elem = this[0]; + + // We need to handle select boxes special + if ( jQuery.nodeName( elem, "select" ) ) { + var index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type == "select-one"; + + // Nothing was selected + if ( index < 0 ) + return null; + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + if ( option.selected ) { + // Get the specifc value for the option + value = jQuery.browser.msie && !option.attributes.value.specified ? option.text : option.value; + + // We don't need an array for one selects + if ( one ) + return value; + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + + // Everything else, we just grab the value + } else + return (this[0].value || "").replace(/\r/g, ""); + + } + + return undefined; + } + + return this.each(function(){ + if ( this.nodeType != 1 ) + return; + + if ( value.constructor == Array && /radio|checkbox/.test( this.type ) ) + this.checked = (jQuery.inArray(this.value, value) >= 0 || + jQuery.inArray(this.name, value) >= 0); + + else if ( jQuery.nodeName( this, "select" ) ) { + var values = value.constructor == Array ? + value : + [ value ]; + + jQuery( "option", this ).each(function(){ + this.selected = (jQuery.inArray( this.value, values ) >= 0 || + jQuery.inArray( this.text, values ) >= 0); + }); + + if ( !values.length ) + this.selectedIndex = -1; + + } else + this.value = value; + }); + }, + + html: function( value ) { + return value == undefined ? + (this.length ? + this[0].innerHTML : + null) : + this.empty().append( value ); + }, + + replaceWith: function( value ) { + return this.after( value ).remove(); + }, + + eq: function( i ) { + return this.slice( i, i + 1 ); + }, + + slice: function() { + return this.pushStack( Array.prototype.slice.apply( this, arguments ) ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function(elem, i){ + return callback.call( elem, i, elem ); + })); + }, + + andSelf: function() { + return this.add( this.prevObject ); + }, + + data: function( key, value ){ + var parts = key.split("."); + parts[1] = parts[1] ? "." + parts[1] : ""; + + if ( value == null ) { + var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); + + if ( data == undefined && this.length ) + data = jQuery.data( this[0], key ); + + return data == null && parts[1] ? + this.data( parts[0] ) : + data; + } else + return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){ + jQuery.data( this, key, value ); + }); + }, + + removeData: function( key ){ + return this.each(function(){ + jQuery.removeData( this, key ); + }); + }, + + domManip: function( args, table, reverse, callback ) { + var clone = this.length > 1, elems; + + return this.each(function(){ + if ( !elems ) { + elems = jQuery.clean( args, this.ownerDocument ); + + if ( reverse ) + elems.reverse(); + } + + var obj = this; + + if ( table && jQuery.nodeName( this, "table" ) && jQuery.nodeName( elems[0], "tr" ) ) + obj = this.getElementsByTagName("tbody")[0] || this.appendChild( this.ownerDocument.createElement("tbody") ); + + var scripts = jQuery( [] ); + + jQuery.each(elems, function(){ + var elem = clone ? + jQuery( this ).clone( true )[0] : + this; + + // execute all scripts after the elements have been injected + if ( jQuery.nodeName( elem, "script" ) ) { + scripts = scripts.add( elem ); + } else { + // Remove any inner scripts for later evaluation + if ( elem.nodeType == 1 ) + scripts = scripts.add( jQuery( "script", elem ).remove() ); + + // Inject the elements into the document + callback.call( obj, elem ); + } + }); + + scripts.each( evalScript ); + }); + } +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.prototype.init.prototype = jQuery.prototype; + +function evalScript( i, elem ) { + if ( elem.src ) + jQuery.ajax({ + url: elem.src, + async: false, + dataType: "script" + }); + + else + jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); + + if ( elem.parentNode ) + elem.parentNode.removeChild( elem ); +} + +jQuery.extend = jQuery.fn.extend = function() { + // copy reference to target object + var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options; + + // Handle a deep copy situation + if ( target.constructor == Boolean ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target != "object" && typeof target != "function" ) + target = {}; + + // extend jQuery itself if only one argument is passed + if ( length == 1 ) { + target = this; + i = 0; + } + + for ( ; i < length; i++ ) + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) + // Extend the base object + for ( var name in options ) { + // Prevent never-ending loop + if ( target === options[ name ] ) + continue; + + // Recurse if we're merging object values + if ( deep && options[ name ] && typeof options[ name ] == "object" && target[ name ] && !options[ name ].nodeType ) + target[ name ] = jQuery.extend( deep, target[ name ], options[ name ] ); + + // Don't bring in undefined values + else if ( options[ name ] != undefined ) + target[ name ] = options[ name ]; + + } + + // Return the modified object + return target; +}; + +var expando = "jQuery" + (new Date()).getTime(), uuid = 0, windowData = {}; + +// exclude the following css properties to add px +var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i; + +jQuery.extend({ + noConflict: function( deep ) { + window.$ = _$; + + if ( deep ) + window.jQuery = _jQuery; + + return jQuery; + }, + + // See test/unit/core.js for details concerning this function. + isFunction: function( fn ) { + return !!fn && typeof fn != "string" && !fn.nodeName && + fn.constructor != Array && /function/i.test( fn + "" ); + }, + + // check if an element is in a (or is an) XML document + isXMLDoc: function( elem ) { + return elem.documentElement && !elem.body || + elem.tagName && elem.ownerDocument && !elem.ownerDocument.body; + }, + + // Evalulates a script in a global context + globalEval: function( data ) { + data = jQuery.trim( data ); + + if ( data ) { + // Inspired by code by Andrea Giammarchi + // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html + var head = document.getElementsByTagName("head")[0] || document.documentElement, + script = document.createElement("script"); + + script.type = "text/javascript"; + if ( jQuery.browser.msie ) + script.text = data; + else + script.appendChild( document.createTextNode( data ) ); + + head.appendChild( script ); + head.removeChild( script ); + } + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase(); + }, + + cache: {}, + + data: function( elem, name, data ) { + elem = elem == window ? + windowData : + elem; + + var id = elem[ expando ]; + + // Compute a unique ID for the element + if ( !id ) + id = elem[ expando ] = ++uuid; + + // Only generate the data cache if we're + // trying to access or manipulate it + if ( name && !jQuery.cache[ id ] ) + jQuery.cache[ id ] = {}; + + // Prevent overriding the named cache with undefined values + if ( data != undefined ) + jQuery.cache[ id ][ name ] = data; + + // Return the named cache data, or the ID for the element + return name ? + jQuery.cache[ id ][ name ] : + id; + }, + + removeData: function( elem, name ) { + elem = elem == window ? + windowData : + elem; + + var id = elem[ expando ]; + + // If we want to remove a specific section of the element's data + if ( name ) { + if ( jQuery.cache[ id ] ) { + // Remove the section of cache data + delete jQuery.cache[ id ][ name ]; + + // If we've removed all the data, remove the element's cache + name = ""; + + for ( name in jQuery.cache[ id ] ) + break; + + if ( !name ) + jQuery.removeData( elem ); + } + + // Otherwise, we want to remove all of the element's data + } else { + // Clean up the element expando + try { + delete elem[ expando ]; + } catch(e){ + // IE has trouble directly removing the expando + // but it's ok with using removeAttribute + if ( elem.removeAttribute ) + elem.removeAttribute( expando ); + } + + // Completely remove the data cache + delete jQuery.cache[ id ]; + } + }, + + // args is for internal usage only + each: function( object, callback, args ) { + if ( args ) { + if ( object.length == undefined ) { + for ( var name in object ) + if ( callback.apply( object[ name ], args ) === false ) + break; + } else + for ( var i = 0, length = object.length; i < length; i++ ) + if ( callback.apply( object[ i ], args ) === false ) + break; + + // A special, fast, case for the most common use of each + } else { + if ( object.length == undefined ) { + for ( var name in object ) + if ( callback.call( object[ name ], name, object[ name ] ) === false ) + break; + } else + for ( var i = 0, length = object.length, value = object[0]; + i < length && callback.call( value, i, value ) !== false; value = object[++i] ){} + } + + return object; + }, + + prop: function( elem, value, type, i, name ) { + // Handle executable functions + if ( jQuery.isFunction( value ) ) + value = value.call( elem, i ); + + // Handle passing in a number to a CSS property + return value && value.constructor == Number && type == "curCSS" && !exclude.test( name ) ? + value + "px" : + value; + }, + + className: { + // internal only, use addClass("class") + add: function( elem, classNames ) { + jQuery.each((classNames || "").split(/\s+/), function(i, className){ + if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) ) + elem.className += (elem.className ? " " : "") + className; + }); + }, + + // internal only, use removeClass("class") + remove: function( elem, classNames ) { + if (elem.nodeType == 1) + elem.className = classNames != undefined ? + jQuery.grep(elem.className.split(/\s+/), function(className){ + return !jQuery.className.has( classNames, className ); + }).join(" ") : + ""; + }, + + // internal only, use is(".class") + has: function( elem, className ) { + return jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1; + } + }, + + // A method for quickly swapping in/out CSS properties to get correct calculations + swap: function( elem, options, callback ) { + var old = {}; + // Remember the old values, and insert the new ones + for ( var name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + callback.call( elem ); + + // Revert the old values + for ( var name in options ) + elem.style[ name ] = old[ name ]; + }, + + css: function( elem, name, force ) { + if ( name == "width" || name == "height" ) { + var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ]; + + function getWH() { + val = name == "width" ? elem.offsetWidth : elem.offsetHeight; + var padding = 0, border = 0; + jQuery.each( which, function() { + padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0; + border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0; + }); + val -= Math.round(padding + border); + } + + if ( jQuery(elem).is(":visible") ) + getWH(); + else + jQuery.swap( elem, props, getWH ); + + return Math.max(0, val); + } + + return jQuery.curCSS( elem, name, force ); + }, + + curCSS: function( elem, name, force ) { + var ret; + + // A helper method for determining if an element's values are broken + function color( elem ) { + if ( !jQuery.browser.safari ) + return false; + + var ret = document.defaultView.getComputedStyle( elem, null ); + return !ret || ret.getPropertyValue("color") == ""; + } + + // We need to handle opacity special in IE + if ( name == "opacity" && jQuery.browser.msie ) { + ret = jQuery.attr( elem.style, "opacity" ); + + return ret == "" ? + "1" : + ret; + } + // Opera sometimes will give the wrong display answer, this fixes it, see #2037 + if ( jQuery.browser.opera && name == "display" ) { + var save = elem.style.outline; + elem.style.outline = "0 solid black"; + elem.style.outline = save; + } + + // Make sure we're using the right name for getting the float value + if ( name.match( /float/i ) ) + name = styleFloat; + + if ( !force && elem.style && elem.style[ name ] ) + ret = elem.style[ name ]; + + else if ( document.defaultView && document.defaultView.getComputedStyle ) { + + // Only "float" is needed here + if ( name.match( /float/i ) ) + name = "float"; + + name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase(); + + var getComputedStyle = document.defaultView.getComputedStyle( elem, null ); + + if ( getComputedStyle && !color( elem ) ) + ret = getComputedStyle.getPropertyValue( name ); + + // If the element isn't reporting its values properly in Safari + // then some display: none elements are involved + else { + var swap = [], stack = []; + + // Locate all of the parent display: none elements + for ( var a = elem; a && color(a); a = a.parentNode ) + stack.unshift(a); + + // Go through and make them visible, but in reverse + // (It would be better if we knew the exact display type that they had) + for ( var i = 0; i < stack.length; i++ ) + if ( color( stack[ i ] ) ) { + swap[ i ] = stack[ i ].style.display; + stack[ i ].style.display = "block"; + } + + // Since we flip the display style, we have to handle that + // one special, otherwise get the value + ret = name == "display" && swap[ stack.length - 1 ] != null ? + "none" : + ( getComputedStyle && getComputedStyle.getPropertyValue( name ) ) || ""; + + // Finally, revert the display styles back + for ( var i = 0; i < swap.length; i++ ) + if ( swap[ i ] != null ) + stack[ i ].style.display = swap[ i ]; + } + + // We should always get a number back from opacity + if ( name == "opacity" && ret == "" ) + ret = "1"; + + } else if ( elem.currentStyle ) { + var camelCase = name.replace(/\-(\w)/g, function(all, letter){ + return letter.toUpperCase(); + }); + + ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ]; + + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) { + // Remember the original values + var style = elem.style.left, runtimeStyle = elem.runtimeStyle.left; + + // Put in the new values to get a computed value out + elem.runtimeStyle.left = elem.currentStyle.left; + elem.style.left = ret || 0; + ret = elem.style.pixelLeft + "px"; + + // Revert the changed values + elem.style.left = style; + elem.runtimeStyle.left = runtimeStyle; + } + } + + return ret; + }, + + clean: function( elems, context ) { + var ret = []; + context = context || document; + // !context.createElement fails in IE with an error but returns typeof 'object' + if (typeof context.createElement == 'undefined') + context = context.ownerDocument || context[0] && context[0].ownerDocument || document; + + jQuery.each(elems, function(i, elem){ + if ( !elem ) + return; + + if ( elem.constructor == Number ) + elem = elem.toString(); + + // Convert html string into DOM nodes + if ( typeof elem == "string" ) { + // Fix "XHTML"-style tags in all browsers + elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){ + return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ? + all : + front + "></" + tag + ">"; + }); + + // Trim whitespace, otherwise indexOf won't work as expected + var tags = jQuery.trim( elem ).toLowerCase(), div = context.createElement("div"); + + var wrap = + // option or optgroup + !tags.indexOf("<opt") && + [ 1, "<select multiple='multiple'>", "</select>" ] || + + !tags.indexOf("<leg") && + [ 1, "<fieldset>", "</fieldset>" ] || + + tags.match(/^<(thead|tbody|tfoot|colg|cap)/) && + [ 1, "<table>", "</table>" ] || + + !tags.indexOf("<tr") && + [ 2, "<table><tbody>", "</tbody></table>" ] || + + // <thead> matched above + (!tags.indexOf("<td") || !tags.indexOf("<th")) && + [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ] || + + !tags.indexOf("<col") && + [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ] || + + // IE can't serialize <link> and <script> tags normally + jQuery.browser.msie && + [ 1, "div<div>", "</div>" ] || + + [ 0, "", "" ]; + + // Go to html and back, then peel off extra wrappers + div.innerHTML = wrap[1] + elem + wrap[2]; + + // Move to the right depth + while ( wrap[0]-- ) + div = div.lastChild; + + // Remove IE's autoinserted <tbody> from table fragments + if ( jQuery.browser.msie ) { + + // String was a <table>, *may* have spurious <tbody> + var tbody = !tags.indexOf("<table") && tags.indexOf("<tbody") < 0 ? + div.firstChild && div.firstChild.childNodes : + + // String was a bare <thead> or <tfoot> + wrap[1] == "<table>" && tags.indexOf("<tbody") < 0 ? + div.childNodes : + []; + + for ( var j = tbody.length - 1; j >= 0 ; --j ) + if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) + tbody[ j ].parentNode.removeChild( tbody[ j ] ); + + // IE completely kills leading whitespace when innerHTML is used + if ( /^\s/.test( elem ) ) + div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild ); + + } + + elem = jQuery.makeArray( div.childNodes ); + } + + if ( elem.length === 0 && (!jQuery.nodeName( elem, "form" ) && !jQuery.nodeName( elem, "select" )) ) + return; + + if ( elem[0] == undefined || jQuery.nodeName( elem, "form" ) || elem.options ) + ret.push( elem ); + + else + ret = jQuery.merge( ret, elem ); + + }); + + return ret; + }, + + attr: function( elem, name, value ) { + // don't set attributes on text and comment nodes + if (!elem || elem.nodeType == 3 || elem.nodeType == 8) + return undefined; + + var fix = jQuery.isXMLDoc( elem ) ? + {} : + jQuery.props; + + // Safari mis-reports the default selected property of a hidden option + // Accessing the parent's selectedIndex property fixes it + if ( name == "selected" && jQuery.browser.safari ) + elem.parentNode.selectedIndex; + + // Certain attributes only work when accessed via the old DOM 0 way + if ( fix[ name ] ) { + if ( value != undefined ) + elem[ fix[ name ] ] = value; + + return elem[ fix[ name ] ]; + + } else if ( jQuery.browser.msie && name == "style" ) + return jQuery.attr( elem.style, "cssText", value ); + + else if ( value == undefined && jQuery.browser.msie && jQuery.nodeName( elem, "form" ) && (name == "action" || name == "method") ) + return elem.getAttributeNode( name ).nodeValue; + + // IE elem.getAttribute passes even for style + else if ( elem.tagName ) { + + if ( value != undefined ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( name == "type" && jQuery.nodeName( elem, "input" ) && elem.parentNode ) + throw "type property can't be changed"; + + // convert the value to a string (all browsers do this but IE) see #1070 + elem.setAttribute( name, "" + value ); + } + + if ( jQuery.browser.msie && /href|src/.test( name ) && !jQuery.isXMLDoc( elem ) ) + return elem.getAttribute( name, 2 ); + + return elem.getAttribute( name ); + + // elem is actually elem.style ... set the style + } else { + // IE actually uses filters for opacity + if ( name == "opacity" && jQuery.browser.msie ) { + if ( value != undefined ) { + // IE has trouble with opacity if it does not have layout + // Force it by setting the zoom level + elem.zoom = 1; + + // Set the alpha filter to set the opacity + elem.filter = (elem.filter || "").replace( /alpha\([^)]*\)/, "" ) + + (parseFloat( value ).toString() == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")"); + } + + return elem.filter && elem.filter.indexOf("opacity=") >= 0 ? + (parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100).toString() : + ""; + } + + name = name.replace(/-([a-z])/ig, function(all, letter){ + return letter.toUpperCase(); + }); + + if ( value != undefined ) + elem[ name ] = value; + + return elem[ name ]; + } + }, + + trim: function( text ) { + return (text || "").replace( /^\s+|\s+$/g, "" ); + }, + + makeArray: function( array ) { + var ret = []; + + // Need to use typeof to fight Safari childNodes crashes + if ( array.constructor != Array ) + for ( var i = 0, length = array.length; i < length; i++ ) + ret.push( array[ i ] ); + else + ret = array.slice( 0 ); + + return ret; + }, + + inArray: function( elem, array ) { + for ( var i = 0, length = array.length; i < length; i++ ) + if ( array[ i ] == elem ) + return i; + + return -1; + }, + + merge: function( first, second ) { + // We have to loop this way because IE & Opera overwrite the length + // expando of getElementsByTagName + + // Also, we need to make sure that the correct elements are being returned + // (IE returns comment nodes in a '*' query) + if ( jQuery.browser.msie ) { + for ( var i = 0; second[ i ]; i++ ) + if ( second[ i ].nodeType != 8 ) + first.push( second[ i ] ); + + } else + for ( var i = 0; second[ i ]; i++ ) + first.push( second[ i ] ); + + return first; + }, + + unique: function( array ) { + var ret = [], done = {}; + + try { + + for ( var i = 0, length = array.length; i < length; i++ ) { + var id = jQuery.data( array[ i ] ); + + if ( !done[ id ] ) { + done[ id ] = true; + ret.push( array[ i ] ); + } + } + + } catch( e ) { + ret = array; + } + + return ret; + }, + + grep: function( elems, callback, inv ) { + var ret = []; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) + if ( !inv && callback( elems[ i ], i ) || inv && !callback( elems[ i ], i ) ) + ret.push( elems[ i ] ); + + return ret; + }, + + map: function( elems, callback ) { + var ret = []; + + // Go through the array, translating each of the items to their + // new value (or values). + for ( var i = 0, length = elems.length; i < length; i++ ) { + var value = callback( elems[ i ], i ); + + if ( value !== null && value != undefined ) { + if ( value.constructor != Array ) + value = [ value ]; + + ret = ret.concat( value ); + } + } + + return ret; + } +}); + +var userAgent = navigator.userAgent.toLowerCase(); + +// Figure out what browser is being used +jQuery.browser = { + version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1], + safari: /webkit/.test( userAgent ), + opera: /opera/.test( userAgent ), + msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ), + mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent ) +}; + +var styleFloat = jQuery.browser.msie ? + "styleFloat" : + "cssFloat"; + +jQuery.extend({ + // Check to see if the W3C box model is being used + boxModel: !jQuery.browser.msie || document.compatMode == "CSS1Compat", + + props: { + "for": "htmlFor", + "class": "className", + "float": styleFloat, + cssFloat: styleFloat, + styleFloat: styleFloat, + innerHTML: "innerHTML", + className: "className", + value: "value", + disabled: "disabled", + checked: "checked", + readonly: "readOnly", + selected: "selected", + maxlength: "maxLength", + selectedIndex: "selectedIndex", + defaultValue: "defaultValue", + tagName: "tagName", + nodeName: "nodeName" + } +}); + +jQuery.each({ + parent: function(elem){return elem.parentNode;}, + parents: function(elem){return jQuery.dir(elem,"parentNode");}, + next: function(elem){return jQuery.nth(elem,2,"nextSibling");}, + prev: function(elem){return jQuery.nth(elem,2,"previousSibling");}, + nextAll: function(elem){return jQuery.dir(elem,"nextSibling");}, + prevAll: function(elem){return jQuery.dir(elem,"previousSibling");}, + siblings: function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);}, + children: function(elem){return jQuery.sibling(elem.firstChild);}, + contents: function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);} +}, function(name, fn){ + jQuery.fn[ name ] = function( selector ) { + var ret = jQuery.map( this, fn ); + + if ( selector && typeof selector == "string" ) + ret = jQuery.multiFilter( selector, ret ); + + return this.pushStack( jQuery.unique( ret ) ); + }; +}); + +jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function(name, original){ + jQuery.fn[ name ] = function() { + var args = arguments; + + return this.each(function(){ + for ( var i = 0, length = args.length; i < length; i++ ) + jQuery( args[ i ] )[ original ]( this ); + }); + }; +}); + +jQuery.each({ + removeAttr: function( name ) { + jQuery.attr( this, name, "" ); + if (this.nodeType == 1) + this.removeAttribute( name ); + }, + + addClass: function( classNames ) { + jQuery.className.add( this, classNames ); + }, + + removeClass: function( classNames ) { + jQuery.className.remove( this, classNames ); + }, + + toggleClass: function( classNames ) { + jQuery.className[ jQuery.className.has( this, classNames ) ? "remove" : "add" ]( this, classNames ); + }, + + remove: function( selector ) { + if ( !selector || jQuery.filter( selector, [ this ] ).r.length ) { + // Prevent memory leaks + jQuery( "*", this ).add(this).each(function(){ + jQuery.event.remove(this); + jQuery.removeData(this); + }); + if (this.parentNode) + this.parentNode.removeChild( this ); + } + }, + + empty: function() { + // Remove element nodes and prevent memory leaks + jQuery( ">*", this ).remove(); + + // Remove any remaining nodes + while ( this.firstChild ) + this.removeChild( this.firstChild ); + } +}, function(name, fn){ + jQuery.fn[ name ] = function(){ + return this.each( fn, arguments ); + }; +}); + +jQuery.each([ "Height", "Width" ], function(i, name){ + var type = name.toLowerCase(); + + jQuery.fn[ type ] = function( size ) { + // Get window width or height + return this[0] == window ? + // Opera reports document.body.client[Width/Height] properly in both quirks and standards + jQuery.browser.opera && document.body[ "client" + name ] || + + // Safari reports inner[Width/Height] just fine (Mozilla and Opera include scroll bar widths) + jQuery.browser.safari && window[ "inner" + name ] || + + // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode + document.compatMode == "CSS1Compat" && document.documentElement[ "client" + name ] || document.body[ "client" + name ] : + + // Get document width or height + this[0] == document ? + // Either scroll[Width/Height] or offset[Width/Height], whichever is greater + Math.max( + Math.max(document.body["scroll" + name], document.documentElement["scroll" + name]), + Math.max(document.body["offset" + name], document.documentElement["offset" + name]) + ) : + + // Get or set width or height on the element + size == undefined ? + // Get width or height on the element + (this.length ? jQuery.css( this[0], type ) : null) : + + // Set the width or height on the element (default to pixels if value is unitless) + 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: { + "": function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);}, + "#": function(a,i,m){return a.getAttribute("id")==m[2];}, + ":": { + // Position Checks + lt: function(a,i,m){return i<m[3]-0;}, + gt: function(a,i,m){return i>m[3]-0;}, + nth: function(a,i,m){return m[3]-0==i;}, + eq: function(a,i,m){return m[3]-0==i;}, + first: function(a,i){return i==0;}, + last: function(a,i,m,r){return i==r.length-1;}, + even: function(a,i){return i%2==0;}, + odd: function(a,i){return i%2;}, + + // Child Checks + "first-child": function(a){return a.parentNode.getElementsByTagName("*")[0]==a;}, + "last-child": function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;}, + "only-child": function(a){return !jQuery.nth(a.parentNode.lastChild,2,"previousSibling");}, + + // Parent Checks + parent: function(a){return a.firstChild;}, + empty: function(a){return !a.firstChild;}, + + // Text Check + contains: function(a,i,m){return (a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;}, + + // Visibility + visible: function(a){return "hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";}, + hidden: function(a){return "hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";}, + + // Form attributes + enabled: function(a){return !a.disabled;}, + disabled: function(a){return a.disabled;}, + checked: function(a){return a.checked;}, + selected: function(a){return a.selected||jQuery.attr(a,"selected");}, + + // Form elements + text: function(a){return "text"==a.type;}, + radio: function(a){return "radio"==a.type;}, + checkbox: function(a){return "checkbox"==a.type;}, + file: function(a){return "file"==a.type;}, + password: function(a){return "password"==a.type;}, + submit: function(a){return "submit"==a.type;}, + image: function(a){return "image"==a.type;}, + reset: function(a){return "reset"==a.type;}, + button: function(a){return "button"==a.type||jQuery.nodeName(a,"button");}, + input: function(a){return /input|select|textarea|button/i.test(a.nodeName);}, + + // :has() + has: function(a,i,m){return jQuery.find(m[3],a).length;}, + + // :header + header: function(a){return /h\d/i.test(a.nodeName);}, + + // :animated + animated: function(a){return 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 ]; + + // check to make sure context is a DOM element or a document + if ( context && context.nodeType != 1 && context.nodeType != 9) + return [ ]; + + // Set the correct context (if none is provided) + context = context || document; + + // Initialize the search + var ret = [context], done = [], last, nodeName; + + // 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 ) { + 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) ) + 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 merge = {}; + nodeName = m[2].toUpperCase(); + 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 ) { + 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 <object>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" ) + // optimize if only one selector found (most common case) + r = isSimple.test( m[3] ) ? + jQuery.filter(m[3], r, true).r : + jQuery( r ).not( m[3] ); + + // 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 = [], + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( + m[3] == "even" && "2n" || m[3] == "odd" && "2n+1" || + !/\D/.test(m[3]) && "0n+" + m[3] || m[3]), + // calculate the numbers (first)n+(last) including if they are negative + first = (test[1] + (test[2] || 1)) - 0, last = test[3] - 0; + + // loop through all the elements left in the jQuery object + 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 == 0 ) { + if ( node.nodeIndex == last ) + add = true; + } else if ( (node.nodeIndex - last) % first == 0 && (node.nodeIndex - last) / first >= 0 ) + add = true; + + if ( add ^ not ) + tmp.push( node ); + } + + r = tmp; + + // Otherwise, find the expression to execute + } else { + var fn = jQuery.expr[ m[1] ]; + if ( typeof fn == "object" ) + fn = fn[ m[2] ]; + + if ( typeof fn == "string" ) + fn = eval("false||function(a,i){return " + fn + ";}"); + + // Execute it against the current filter + r = jQuery.grep( r, function(elem, i){ + return fn(elem, i, m, r); + }, 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(elem, types, handler, data) { + if ( elem.nodeType == 3 || elem.nodeType == 8 ) + return; + + // For whatever reason, IE has trouble passing the window object + // around, causing it to be cloned in the process + if ( jQuery.browser.msie && elem.setInterval != undefined ) + elem = 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; + } + + // Init the element's event structure + var events = jQuery.data(elem, "events") || jQuery.data(elem, "events", {}), + handle = jQuery.data(elem, "handle") || jQuery.data(elem, "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(arguments.callee.elem, arguments); + + return val; + }); + // Add elem as a property of the handle function + // This is to prevent a memory leak with non-native + // event in IE. + handle.elem = elem; + + // Handle multiple events seperated by a space + // jQuery(...).bind("mouseover mouseout", fn); + jQuery.each(types.split(/\s+/), function(index, type) { + // Namespaced event handlers + var parts = type.split("."); + type = parts[0]; + handler.type = parts[1]; + + // Get the current list of functions bound to this event + var handlers = events[type]; + + // Init the event handler queue + if (!handlers) { + handlers = events[type] = {}; + + // Check for a special event handler + // Only use addEventListener/attachEvent if the special + // events handler returns false + if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem) === false ) { + // Bind the global event handler to the element + if (elem.addEventListener) + elem.addEventListener(type, handle, false); + else if (elem.attachEvent) + elem.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 + jQuery.event.global[type] = true; + }); + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + guid: 1, + global: {}, + + // Detach an event or set of events from an element + remove: function(elem, types, handler) { + // don't do events on text and comment nodes + if ( elem.nodeType == 3 || elem.nodeType == 8 ) + return; + + var events = jQuery.data(elem, "events"), ret, index; + + if ( events ) { + // Unbind all events for the element + if ( types == undefined || (typeof types == "string" && types.charAt(0) == ".") ) + for ( var type in events ) + this.remove( elem, type + (types || "") ); + else { + // types is actually an event object here + if ( types.type ) { + handler = types.handler; + types = types.type; + } + + // Handle multiple events seperated by a space + // jQuery(...).unbind("mouseover mouseout", fn); + jQuery.each(types.split(/\s+/), function(index, type){ + // Namespaced event handlers + var parts = type.split("."); + type = parts[0]; + + 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 ( !jQuery.event.special[type] || jQuery.event.special[type].teardown.call(elem) === false ) { + if (elem.removeEventListener) + elem.removeEventListener(type, jQuery.data(elem, "handle"), false); + else if (elem.detachEvent) + elem.detachEvent("on" + type, jQuery.data(elem, "handle")); + } + ret = null; + delete events[type]; + } + } + }); + } + + // Remove the expando if it's no longer used + for ( ret in events ) break; + if ( !ret ) { + var handle = jQuery.data( elem, "handle" ); + if ( handle ) handle.elem = null; + jQuery.removeData( elem, "events" ); + jQuery.removeData( elem, "handle" ); + } + } + }, + + trigger: function(type, data, elem, donative, extra) { + // Clone the incoming data, if any + data = jQuery.makeArray(data || []); + + if ( type.indexOf("!") >= 0 ) { + type = type.slice(0, -1); + var exclusive = true; + } + + // Handle a global trigger + if ( !elem ) { + // 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 { + // don't do events on text and comment nodes + if ( elem.nodeType == 3 || elem.nodeType == 8 ) + return undefined; + + var val, ret, fn = jQuery.isFunction( elem[ 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: elem }) ); + + // Enforce the right trigger type + data[0].type = type; + if ( exclusive ) + data[0].exclusive = true; + + // Trigger the event + if ( jQuery.isFunction( jQuery.data(elem, "handle") ) ) + val = jQuery.data(elem, "handle").apply( elem, data ); + + // Handle triggering native .onfoo handlers + if ( !fn && elem["on"+type] && elem["on"+type].apply( elem, data ) === false ) + val = false; + + // Extra functions don't get the custom event object + if ( event ) + data.shift(); + + // Handle triggering of extra function + if ( extra && jQuery.isFunction( extra ) ) { + // call the extra function and tack the current return value on the end for possible inspection + ret = extra.apply( elem, val == null ? data : data.concat( val ) ); + // if anything is returned, give it precedence and have it overwrite the previous value + if (ret !== undefined) + val = ret; + } + + // Trigger the native events (except for clicks on links) + if ( fn && donative !== false && val !== false && !(jQuery.nodeName(elem, 'a') && type == "click") ) { + this.triggered = true; + try { + elem[ type ](); + // prevent IE from throwing an error for some hidden elements + } catch (e) {} + } + + 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] && !event.exclusive || 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.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either + + // check if target is a textnode (safari) + if ( 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.clientTop || 0); + } + + // Add which for key events + if ( !event.which && ((event.charCode || event.charCode === 0) ? 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; + }, + + special: { + ready: { + setup: function() { + // Make sure the ready event is setup + bindReady(); + return; + }, + + teardown: function() { return; } + }, + + mouseenter: { + setup: function() { + if ( jQuery.browser.msie ) return false; + jQuery(this).bind("mouseover", jQuery.event.special.mouseenter.handler); + return true; + }, + + teardown: function() { + if ( jQuery.browser.msie ) return false; + jQuery(this).unbind("mouseover", jQuery.event.special.mouseenter.handler); + return true; + }, + + handler: function(event) { + // If we actually just moused on to a sub-element, ignore it + if ( withinElement(event, this) ) return true; + // Execute the right handlers by setting the event type to mouseenter + arguments[0].type = "mouseenter"; + return jQuery.event.handle.apply(this, arguments); + } + }, + + mouseleave: { + setup: function() { + if ( jQuery.browser.msie ) return false; + jQuery(this).bind("mouseout", jQuery.event.special.mouseleave.handler); + return true; + }, + + teardown: function() { + if ( jQuery.browser.msie ) return false; + jQuery(this).unbind("mouseout", jQuery.event.special.mouseleave.handler); + return true; + }, + + handler: function(event) { + // If we actually just moused on to a sub-element, ignore it + if ( withinElement(event, this) ) return true; + // Execute the right handlers by setting the event type to mouseleave + arguments[0].type = "mouseleave"; + return jQuery.event.handle.apply(this, arguments); + } + } + } +}; + +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 ); + return undefined; + }, + + 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, arguments ) || false; + }); + }, + + hover: function(fnOver, fnOut) { + return this.bind('mouseenter', fnOver).bind('mouseleave', fnOut); + }, + + ready: function(fn) { + // Attach the listeners + bindReady(); + + // If the DOM is already ready + if ( jQuery.isReady ) + // Execute the function immediately + fn.call( document, jQuery ); + + // Otherwise, remember the function for later + else + // Add the function to the wait list + jQuery.readyList.push( function() { return fn.call(this, jQuery); } ); + + return this; + } +}); + +jQuery.extend({ + 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; + } + + // Trigger any bound ready events + jQuery(document).triggerHandler("ready"); + } + } +}); + +var readyBound = false; + +function bindReady(){ + if ( readyBound ) return; + readyBound = true; + + // Mozilla, Opera (see further below for it) and webkit nightlies currently support this event + if ( document.addEventListener && !jQuery.browser.opera) + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", jQuery.ready, false ); + + // If IE is used and is not in a frame + // Continually check to see if the document is ready + if ( jQuery.browser.msie && window == top ) (function(){ + if (jQuery.isReady) return; + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch( error ) { + setTimeout( arguments.callee, 0 ); + return; + } + // and execute any waiting functions + jQuery.ready(); + })(); + + if ( jQuery.browser.opera ) + document.addEventListener( "DOMContentLoaded", function () { + if (jQuery.isReady) return; + for (var i = 0; i < document.styleSheets.length; i++) + if (document.styleSheets[i].disabled) { + setTimeout( arguments.callee, 0 ); + return; + } + // and execute any waiting functions + jQuery.ready(); + }, false); + + if ( jQuery.browser.safari ) { + var numStyles; + (function(){ + if (jQuery.isReady) return; + if ( document.readyState != "loaded" && document.readyState != "complete" ) { + setTimeout( arguments.callee, 0 ); + return; + } + if ( numStyles === undefined ) + numStyles = jQuery("style, link[rel=stylesheet]").length; + if ( document.styleSheets.length != numStyles ) { + setTimeout( arguments.callee, 0 ); + return; + } + // and execute any waiting functions + jQuery.ready(); + })(); + } + + // A fallback to window.onload, that will always work + jQuery.event.add( window, "load", jQuery.ready ); +} + +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); + }; +}); + +// Checks if an event happened on an element within another element +// Used in jQuery.event.special.mouseenter and mouseleave handlers +var withinElement = function(event, elem) { + // Check if mouse(over|out) are still within the same parent element + var parent = event.relatedTarget; + // Traverse up the tree + while ( parent && parent != elem ) try { parent = parent.parentNode; } catch(error) { parent = elem; } + // Return true if we actually just moused on to a sub-element + return parent == elem; +}; + +// Prevent memory leaks in IE +// And prevent errors on refresh with events like mouseover in other browsers +// Window isn't included so as not to unbind existing unload events +jQuery(window).bind("unload", function() { + jQuery("*").add(document).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, + dataType: "html", + 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("<div/>") + // inject the contents of the document in, removing the scripts + // to avoid any 'Permission Denied' errors in IE + .append(res.responseText.replace(/<script(.|\s)*?\/script>/g, "")) + + // Locate the specified elements + .find(selector) : + + // If not, just inject the full result + res.responseText ); + + self.each( callback, [res.responseText, status, res] ); + } + }); + 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, + username: null, + password: null, + accepts: { + xml: "application/xml, text/xml", + html: "text/html", + script: "text/javascript, application/javascript", + json: "application/json, text/javascript", + text: "text/plain", + _default: "*/*" + } + }, + + // Last-Modified header cache for next request + lastModified: {}, + + ajax: function( s ) { + var jsonp, jsre = /=\?(&|$)/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 && s.data.match(jsre) || 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 + "$1"); + s.url = s.url.replace(jsre, "=" + jsonp + "$1"); + + // 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 ( head ) + head.removeChild( script ); + }; + } + + if ( s.dataType == "script" && s.cache == null ) + s.cache = false; + + if ( s.cache === false && s.type.toLowerCase() == "get" ) { + var ts = (new Date()).getTime(); + // try replacing _= if it is there + var ret = s.url.replace(/(\?|&)_=.*?(&|$)/, "$1_=" + ts + "$2"); + // if nothing was replaced, add timestamp to the end + s.url = ret + ((ret == s.url) ? (s.url.match(/\?/) ? "&" : "?") + "_=" + ts : ""); + } + + // 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 with a GET + if ( (!s.url.indexOf("http") || !s.url.indexOf("//")) && s.dataType == "script" && s.type.toLowerCase() == "get" ) { + var head = document.getElementsByTagName("head")[0]; + var script = document.createElement("script"); + script.src = s.url; + if (s.scriptCharset) + script.charset = s.scriptCharset; + + // 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 undefined; + } + + 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, s.username, s.password); + + // Need an extra try/catch for cross domain requests in Firefox 3 + try { + // 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"); + + // Set the Accepts header for the server, depending on the dataType + xml.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ? + s.accepts[ s.dataType ] + ", */*" : + s.accepts._default ); + } catch(e){} + + // 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(); + + 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" ); + } + + // return XMLHttpRequest to allow aborting the request etc. + return xml; + }, + + 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 { + // IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450 + return !r.status && location.protocol == "file:" || + ( r.status >= 200 && r.status < 300 ) || r.status == 304 || r.status == 1223 || + 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 || ""; + if ( jQuery.css(this,"display") == "none" ) { + var elem = jQuery("<" + this.tagName + " />").appendTo("body"); + this.style.display = elem.css("display"); + // handle an edge condition where css is - div { display:none; } or similar + if (this.style.display == "none") + this.style.display = "block"; + elem.remove(); + } + }).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"); + 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(){ + if ( this.nodeType != 1) + return false; + + 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) || ( type && type.constructor == Array )) { + 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(clearQueue, gotoEnd){ + var timers = jQuery.timers; + + if (clearQueue) + this.queue([]); + + this.each(function(){ + // go in reverse order so anything added to the queue during the loop is ignored + for ( var i = timers.length - 1; i >= 0; i-- ) + if ( timers[i].elem == this ) { + if (gotoEnd) + // force the next step to be the last + timers[i](true); + timers.splice(i, 1); + } + }); + + // start the next in the queue if the last step wasn't forced + if (!gotoEnd) + this.dequeue(); + + return this; + } + +}); + +var queue = function( elem, type, array ) { + if ( !elem ) + return undefined; + + type = type || "fx"; + + 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(){ + if ( opt.queue !== false ) + 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: [], + timerId: null, + + 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.css(this.elem, this.prop, force)); + return r && r > -10000 ? r : parseFloat(jQuery.curCSS(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(gotoEnd){ + return self.step(gotoEnd); + } + + t.elem = this.elem; + + jQuery.timers.push(t); + + if ( jQuery.timerId == null ) { + jQuery.timerId = 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( jQuery.timerId ); + jQuery.timerId = null; + } + }, 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(gotoEnd){ + var t = (new Date()).getTime(); + + if ( gotoEnd || 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 && !/adobeair/i.test(userAgent), + 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 7 quirks mode the border width is overwritable by the following css html { border: 0; } + // IE 7 standards mode, the border is always 2px + // This border/offset is typically represented by the clientLeft and clientTop properties + // However, in IE6 and 7 quirks mode the clientLeft and clientTop properties are not updated when overwriting it via CSS + // Therefore this method will be off by 2px in IE while in quirksmode + add( -doc.documentElement.clientLeft, -doc.documentElement.clientTop ); + + // 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 && parent.tagName && !/^body|html$/i.test(parent.tagName) ) { + // Remove parent scroll UNLESS that parent is inline or a table to work around Opera inline/table scrollLeft/Top bug + if ( !/^inline|table.*$/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") != "absolute") ) + 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 }; + } + + function border(elem) { + add( jQuery.curCSS(elem, "borderLeftWidth", true), jQuery.curCSS(elem, "borderTopWidth", true) ); + } + + function add(l, t) { + left += parseInt(l) || 0; + top += parseInt(t) || 0; + } + + return results; +}; + +// Create innerHeight, innerWidth, outerHeight and outerWidth methods +jQuery.each(["Height", "Width"], function(i, name){ + + var tl = name == "Height" ? "Top" : "Left", // top or left + br = name == "Height" ? "Bottom" : "Right"; // bottom or right + + // innerHeight and innerWidth + jQuery.fn["inner" + name] = function(){ + return this[ name.toLowerCase() ]() + + num(this, "padding" + tl) + + num(this, "padding" + br); + }; + + // outerHeight and outerWidth + jQuery.fn["outer" + name] = function(margin) { + return this["inner" + name]() + + num(this, "border" + tl + "Width") + + num(this, "border" + br + "Width") + + (!!margin ? + num(this, "margin" + tl) + num(this, "margin" + br) : 0); + }; + +}); + +function num(elem, prop) { + elem = elem.jquery ? elem[0] : elem; + return elem && parseInt( jQuery.curCSS(elem, prop, true) ) || 0; +}})(); diff --git a/vendors/jquery/ui.base.js b/vendors/jquery/ui.base.js new file mode 100755 index 000000000..36a623912 --- /dev/null +++ b/vendors/jquery/ui.base.js @@ -0,0 +1,204 @@ +/* + * jQuery UI @VERSION + * + * Copyright (c) 2008 Paul Bakaus (ui.jquery.com) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI + * + * $Date: 2008-04-01 09:23:47 -0400 (Tue, 01 Apr 2008) $ + * $Rev: 5174 $ + */ +;(function($) { + + //If the UI scope is not available, add it + $.ui = $.ui || {}; + + //Add methods that are vital for all mouse interaction stuff (plugin registering) + $.extend($.ui, { + plugin: { + add: function(module, option, set) { + var proto = $.ui[module].prototype; + for(var i in set) { + proto.plugins[i] = proto.plugins[i] || []; + proto.plugins[i].push([option, set[i]]); + } + }, + call: function(instance, name, arguments) { + var set = instance.plugins[name]; if(!set) return; + for (var i = 0; i < set.length; i++) { + if (instance.options[set[i][0]]) set[i][1].apply(instance.element, arguments); + } + } + }, + cssCache: {}, + css: function(name) { + if ($.ui.cssCache[name]) return $.ui.cssCache[name]; + var tmp = $('<div class="ui-resizable-gen">').addClass(name).css({position:'absolute', top:'-5000px', left:'-5000px', display:'block'}).appendTo('body'); + + //if (!$.browser.safari) + //tmp.appendTo('body'); + + //Opera and Safari set width and height to 0px instead of auto + //Safari returns rgba(0,0,0,0) when bgcolor is not set + $.ui.cssCache[name] = !!( + (!/auto|default/.test(tmp.css('cursor')) || (/^[1-9]/).test(tmp.css('height')) || (/^[1-9]/).test(tmp.css('width')) || + !(/none/).test(tmp.css('backgroundImage')) || !(/transparent|rgba\(0, 0, 0, 0\)/).test(tmp.css('backgroundColor'))) + ); + try { $('body').get(0).removeChild(tmp.get(0)); } catch(e){} + return $.ui.cssCache[name]; + }, + disableSelection: function(e) { + e.unselectable = "on"; + e.onselectstart = function() { return false; }; + if (e.style) e.style.MozUserSelect = "none"; + }, + enableSelection: function(e) { + e.unselectable = "off"; + e.onselectstart = function() { return true; }; + if (e.style) e.style.MozUserSelect = ""; + }, + hasScroll: function(e, a) { + var scroll = /top/.test(a||"top") ? 'scrollTop' : 'scrollLeft', has = false; + if (e[scroll] > 0) return true; e[scroll] = 1; + has = e[scroll] > 0 ? true : false; e[scroll] = 0; + return has; + } + }); + + /******* fn scope modifications ********/ + + $.each( ['Left', 'Top'], function(i, name) { + if(!$.fn['scroll'+name]) $.fn['scroll'+name] = function(v) { + return v != undefined ? + this.each(function() { this == window || this == document ? window.scrollTo(name == 'Left' ? v : $(window)['scrollLeft'](), name == 'Top' ? v : $(window)['scrollTop']()) : this['scroll'+name] = v; }) : + this[0] == window || this[0] == document ? self[(name == 'Left' ? 'pageXOffset' : 'pageYOffset')] || $.boxModel && document.documentElement['scroll'+name] || document.body['scroll'+name] : this[0][ 'scroll' + name ]; + }; + }); + + var _remove = $.fn.remove; + $.fn.extend({ + position: function() { + var offset = this.offset(); + var offsetParent = this.offsetParent(); + var parentOffset = offsetParent.offset(); + + return { + top: offset.top - num(this[0], 'marginTop') - parentOffset.top - num(offsetParent, 'borderTopWidth'), + left: offset.left - num(this[0], 'marginLeft') - parentOffset.left - num(offsetParent, 'borderLeftWidth') + }; + }, + offsetParent: function() { + var offsetParent = this[0].offsetParent; + while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) && $.css(offsetParent, 'position') == 'static') ) + offsetParent = offsetParent.offsetParent; + return $(offsetParent); + }, + mouseInteraction: function(o) { + return this.each(function() { + new $.ui.mouseInteraction(this, o); + }); + }, + removeMouseInteraction: function(o) { + return this.each(function() { + if($.data(this, "ui-mouse")) + $.data(this, "ui-mouse").destroy(); + }); + }, + remove: function() { + jQuery("*", this).add(this).trigger("remove"); + return _remove.apply(this, arguments ); + } + }); + + function num(el, prop) { + return parseInt($.curCSS(el.jquery?el[0]:el,prop,true))||0; + }; + + + /********** Mouse Interaction Plugin *********/ + + $.ui.mouseInteraction = function(element, options) { + + var self = this; + this.element = element; + + $.data(this.element, "ui-mouse", this); + this.options = $.extend({}, options); + + $(element).bind('mousedown.draggable', function() { return self.click.apply(self, arguments); }); + if($.browser.msie) $(element).attr('unselectable', 'on'); //Prevent text selection in IE + + // prevent draggable-options-delay bug #2553 + $(element).mouseup(function() { + if(self.timer) clearInterval(self.timer); + }); + }; + + $.extend($.ui.mouseInteraction.prototype, { + + destroy: function() { $(this.element).unbind('mousedown.draggable'); }, + trigger: function() { return this.click.apply(this, arguments); }, + click: function(e) { + + if( + e.which != 1 //only left click starts dragging + || $.inArray(e.target.nodeName.toLowerCase(), this.options.dragPrevention || []) != -1 // Prevent execution on defined elements + || (this.options.condition && !this.options.condition.apply(this.options.executor || this, [e, this.element])) //Prevent execution on condition + ) return true; + + var self = this; + var initialize = function() { + self._MP = { left: e.pageX, top: e.pageY }; // Store the click mouse position + $(document).bind('mouseup.draggable', function() { return self.stop.apply(self, arguments); }); + $(document).bind('mousemove.draggable', function() { return self.drag.apply(self, arguments); }); + + if(!self.initalized && Math.abs(self._MP.left-e.pageX) >= self.options.distance || Math.abs(self._MP.top-e.pageY) >= self.options.distance) { + if(self.options.start) self.options.start.call(self.options.executor || self, e, self.element); + if(self.options.drag) self.options.drag.call(self.options.executor || self, e, this.element); //This is actually not correct, but expected + self.initialized = true; + } + }; + + if(this.options.delay) { + if(this.timer) clearInterval(this.timer); + this.timer = setTimeout(initialize, this.options.delay); + } else { + initialize(); + } + + return false; + + }, + stop: function(e) { + + var o = this.options; + if(!this.initialized) return $(document).unbind('mouseup.draggable').unbind('mousemove.draggable'); + + if(this.options.stop) this.options.stop.call(this.options.executor || this, e, this.element); + $(document).unbind('mouseup.draggable').unbind('mousemove.draggable'); + this.initialized = false; + return false; + + }, + drag: function(e) { + + var o = this.options; + if ($.browser.msie && !e.button) return this.stop.apply(this, [e]); // IE mouseup check + + if(!this.initialized && (Math.abs(this._MP.left-e.pageX) >= o.distance || Math.abs(this._MP.top-e.pageY) >= o.distance)) { + if(this.options.start) this.options.start.call(this.options.executor || this, e, this.element); + this.initialized = true; + } else { + if(!this.initialized) return false; + } + + if(o.drag) o.drag.call(this.options.executor || this, e, this.element); + return false; + + } + }); + +})(jQuery); +
\ No newline at end of file diff --git a/vendors/jquery/ui.draggable.js b/vendors/jquery/ui.draggable.js new file mode 100755 index 000000000..d26658176 --- /dev/null +++ b/vendors/jquery/ui.draggable.js @@ -0,0 +1,572 @@ +/* + * jQuery UI Draggable + * + * Copyright (c) 2008 Paul Bakaus + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Draggables + * + * Depends: + * ui.base.js + * + * Revision: $Id: ui.draggable.js 5194 2008-04-04 12:30:10Z paul.bakaus $ + */ +;(function($) { + + $.fn.extend({ + draggable: function(options) { + var args = Array.prototype.slice.call(arguments, 1); + + return this.each(function() { + if (typeof options == "string") { + var drag = $.data(this, "draggable"); + if(drag) drag[options].apply(drag, args); + + } else if(!$.data(this, "draggable")) + new $.ui.draggable(this, options); + }); + } + }); + + $.ui.draggable = function(element, options) { + //Initialize needed constants + var self = this; + + this.element = $(element); + + $.data(element, "draggable", this); + this.element.addClass("ui-draggable"); + + //Prepare the passed options + this.options = $.extend({}, options); + var o = this.options; + $.extend(o, { + helper: o.ghosting == true ? 'clone' : (o.helper || 'original'), + handle : o.handle ? ($(o.handle, element)[0] ? $(o.handle, element) : this.element) : this.element, + appendTo: o.appendTo || 'parent' + }); + + $(element).bind("setData.draggable", function(event, key, value){ + self.options[key] = value; + }).bind("getData.draggable", function(event, key){ + return self.options[key]; + }); + + //Initialize mouse events for interaction + $(o.handle).mouseInteraction({ + executor: this, + delay: o.delay, + distance: o.distance || 1, + dragPrevention: o.cancel || o.cancel === '' ? o.cancel.toLowerCase().split(',') : ['input','textarea','button','select','option'], + start: this.start, + stop: this.stop, + drag: this.drag, + condition: function(e) { return !(e.target.className.indexOf("ui-resizable-handle") != -1 || this.options.disabled); } + }); + + //Position the node + if(o.helper == 'original' && (this.element.css('position') == 'static' || this.element.css('position') == '')) + this.element.css('position', 'relative'); + + //Prepare cursorAt + if(o.cursorAt && o.cursorAt.constructor == Array) + o.cursorAt = { left: o.cursorAt[0], top: o.cursorAt[1] }; + + }; + + $.extend($.ui.draggable.prototype, { + plugins: {}, + ui: function(e) { + return { + helper: this.helper, + position: this.position, + absolutePosition: this.positionAbs, + instance: this, + options: this.options, + element: this.element + }; + }, + propagate: function(n,e) { + $.ui.plugin.call(this, n, [e, this.ui()]); + return this.element.triggerHandler(n == "drag" ? n : "drag"+n, [e, this.ui()], this.options[n]); + }, + destroy: function() { + if(!$.data(this.element[0], 'draggable')) return; + this.options.handle.removeMouseInteraction(); + this.element + .removeClass("ui-draggable ui-draggable-disabled") + .removeData("draggable") + .unbind(".draggable"); + }, + enable: function() { + this.element.removeClass("ui-draggable-disabled"); + this.options.disabled = false; + }, + disable: function() { + this.element.addClass("ui-draggable-disabled"); + this.options.disabled = true; + }, + setContrains: function(minLeft,maxLeft,minTop,maxTop) { + this.minLeft = minLeft; this.maxLeft = maxLeft; + this.minTop = minTop; this.maxTop = maxTop; + this.constrainsSet = true; + }, + checkConstrains: function() { + if(!this.constrainsSet) return; + if(this.position.left < this.minLeft) this.position.left = this.minLeft; + if(this.position.left > this.maxLeft - this.helperProportions.width) this.position.left = this.maxLeft - this.helperProportions.width; + if(this.position.top < this.minTop) this.position.top = this.minTop; + if(this.position.top > this.maxTop - this.helperProportions.height) this.position.top = this.maxTop - this.helperProportions.height; + }, + recallOffset: function(e) { + + var elementPosition = { left: this.elementOffset.left - this.offsetParentOffset.left, top: this.elementOffset.top - this.offsetParentOffset.top }; + var r = this.helper.css('position') == 'relative'; + + //Generate the original position + this.originalPosition = { + left: (r ? parseInt(this.helper.css('left'),10) || 0 : elementPosition.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft)), + top: (r ? parseInt(this.helper.css('top'),10) || 0 : elementPosition.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop)) + }; + + //Generate a flexible offset that will later be subtracted from e.pageX/Y + this.offset = {left: this._pageX - this.originalPosition.left, top: this._pageY - this.originalPosition.top }; + + }, + start: function(e) { + var o = this.options; + if($.ui.ddmanager) $.ui.ddmanager.current = this; + + //Create and append the visible helper + this.helper = typeof o.helper == 'function' ? $(o.helper.apply(this.element[0], [e])) : (o.helper == 'clone' ? this.element.clone().appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo)) : this.element); + if(this.helper[0] != this.element[0]) this.helper.css('position', 'absolute'); + if(!this.helper.parents('body').length) this.helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo)); + + + //Find out the next positioned parent + this.offsetParent = (function(cp) { + while(cp) { + if(cp.style && (/(absolute|relative|fixed)/).test($.css(cp,'position'))) return $(cp); + cp = cp.parentNode ? cp.parentNode : null; + }; return $("body"); + })(this.helper[0].parentNode); + + //Prepare variables for position generation + this.elementOffset = this.element.offset(); + this.offsetParentOffset = this.offsetParent.offset(); + var elementPosition = { left: this.elementOffset.left - this.offsetParentOffset.left, top: this.elementOffset.top - this.offsetParentOffset.top }; + this._pageX = e.pageX; this._pageY = e.pageY; + this.clickOffset = { left: e.pageX - this.elementOffset.left, top: e.pageY - this.elementOffset.top }; + var r = this.helper.css('position') == 'relative'; + + //Generate the original position + this.originalPosition = { + left: (r ? parseInt(this.helper.css('left'),10) || 0 : elementPosition.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft)), + top: (r ? parseInt(this.helper.css('top'),10) || 0 : elementPosition.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop)) + }; + + //If we have a fixed element, we must subtract the scroll offset again + if(this.element.css('position') == 'fixed') { + this.originalPosition.top -= this.offsetParent[0] == document.body ? $(document).scrollTop() : this.offsetParent[0].scrollTop; + this.originalPosition.left -= this.offsetParent[0] == document.body ? $(document).scrollLeft() : this.offsetParent[0].scrollLeft; + } + + //Generate a flexible offset that will later be subtracted from e.pageX/Y + this.offset = {left: e.pageX - this.originalPosition.left, top: e.pageY - this.originalPosition.top }; + + //Substract margins + if(this.element[0] != this.helper[0]) { + this.offset.left += parseInt(this.element.css('marginLeft'),10) || 0; + this.offset.top += parseInt(this.element.css('marginTop'),10) || 0; + } + + //Call plugins and callbacks + this.propagate("start", e); + + this.helperProportions = { width: this.helper.outerWidth(), height: this.helper.outerHeight() }; + if ($.ui.ddmanager && !o.dropBehaviour) $.ui.ddmanager.prepareOffsets(this, e); + + //If we have something in cursorAt, we'll use it + if(o.cursorAt) { + if(o.cursorAt.top != undefined || o.cursorAt.bottom != undefined) { + this.offset.top -= this.clickOffset.top - (o.cursorAt.top != undefined ? o.cursorAt.top : (this.helperProportions.height - o.cursorAt.bottom)); + this.clickOffset.top = (o.cursorAt.top != undefined ? o.cursorAt.top : (this.helperProportions.height - o.cursorAt.bottom)); + } + if(o.cursorAt.left != undefined || o.cursorAt.right != undefined) { + this.offset.left -= this.clickOffset.left - (o.cursorAt.left != undefined ? o.cursorAt.left : (this.helperProportions.width - o.cursorAt.right)); + this.clickOffset.left = (o.cursorAt.left != undefined ? o.cursorAt.left : (this.helperProportions.width - o.cursorAt.right)); + } + } + + return false; + + }, + clear: function() { + if($.ui.ddmanager) $.ui.ddmanager.current = null; + this.helper = null; + }, + stop: function(e) { + + //If we are using droppables, inform the manager about the drop + if ($.ui.ddmanager && !this.options.dropBehaviour) + $.ui.ddmanager.drop(this, e); + + //Call plugins and trigger callbacks + this.propagate("stop", e); + + if(this.cancelHelperRemoval) return false; + if(this.options.helper != 'original') this.helper.remove(); + this.clear(); + + return false; + }, + drag: function(e) { + + //Compute the helpers position + this.position = { top: e.pageY - this.offset.top, left: e.pageX - this.offset.left }; + this.positionAbs = { left: e.pageX - this.clickOffset.left, top: e.pageY - this.clickOffset.top }; + + //Call plugins and callbacks + this.checkConstrains(); + this.position = this.propagate("drag", e) || this.position; + this.checkConstrains(); + + $(this.helper).css({ left: this.position.left+'px', top: this.position.top+'px' }); // Stick the helper to the cursor + if($.ui.ddmanager) $.ui.ddmanager.drag(this, e); + return false; + + } + }); + +/* + * Draggable Extensions + */ + + $.ui.plugin.add("draggable", "cursor", { + start: function(e, ui) { + var t = $('body'); + if (t.css("cursor")) ui.options._cursor = t.css("cursor"); + t.css("cursor", ui.options.cursor); + }, + stop: function(e, ui) { + if (ui.options._cursor) $('body').css("cursor", ui.options._cursor); + } + }); + + $.ui.plugin.add("draggable", "zIndex", { + start: function(e, ui) { + var t = $(ui.helper); + if(t.css("zIndex")) ui.options._zIndex = t.css("zIndex"); + t.css('zIndex', ui.options.zIndex); + }, + stop: function(e, ui) { + if(ui.options._zIndex) $(ui.helper).css('zIndex', ui.options._zIndex); + } + }); + + $.ui.plugin.add("draggable", "opacity", { + start: function(e, ui) { + var t = $(ui.helper); + if(t.css("opacity")) ui.options._opacity = t.css("opacity"); + t.css('opacity', ui.options.opacity); + }, + stop: function(e, ui) { + if(ui.options._opacity) $(ui.helper).css('opacity', ui.options._opacity); + } + }); + + + $.ui.plugin.add("draggable", "revert", { + stop: function(e, ui) { + var self = ui.instance, helper = $(self.helper); + self.cancelHelperRemoval = true; + + $(ui.helper).animate({ left: self.originalPosition.left, top: self.originalPosition.top }, parseInt(ui.options.revert, 10) || 500, function() { + if(ui.options.helper != 'original') helper.remove(); + if (!helper) self.clear(); + }); + } + }); + + $.ui.plugin.add("draggable", "iframeFix", { + start: function(e, ui) { + + var o = ui.options; + if(ui.instance.slowMode) return; // Make clones on top of iframes (only if we are not in slowMode) + + if(o.iframeFix.constructor == Array) { + for(var i=0;i<o.iframeFix.length;i++) { + var co = $(o.iframeFix[i]).offset({ border: false }); + $('<div class="DragDropIframeFix"" style="background: #fff;"></div>').css("width", $(o.iframeFix[i])[0].offsetWidth+"px").css("height", $(o.iframeFix[i])[0].offsetHeight+"px").css("position", "absolute").css("opacity", "0.001").css("z-index", "1000").css("top", co.top+"px").css("left", co.left+"px").appendTo("body"); + } + } else { + $("iframe").each(function() { + var co = $(this).offset({ border: false }); + $('<div class="DragDropIframeFix" style="background: #fff;"></div>').css("width", this.offsetWidth+"px").css("height", this.offsetHeight+"px").css("position", "absolute").css("opacity", "0.001").css("z-index", "1000").css("top", co.top+"px").css("left", co.left+"px").appendTo("body"); + }); + } + + }, + stop: function(e, ui) { + if(ui.options.iframeFix) $("div.DragDropIframeFix").each(function() { this.parentNode.removeChild(this); }); //Remove frame helpers + } + }); + + $.ui.plugin.add("draggable", "containment", { + start: function(e, ui) { + + var o = ui.options; + var self = ui.instance; + if((o.containment.left != undefined || o.containment.constructor == Array) && !o._containment) return; + if(!o._containment) o._containment = o.containment; + + if(o._containment == 'parent') o._containment = this[0].parentNode; + if(o._containment == 'document') { + o.containment = [ + 0, + 0, + $(document).width(), + ($(document).height() || document.body.parentNode.scrollHeight) + ]; + } else { //I'm a node, so compute top/left/right/bottom + + var ce = $(o._containment)[0]; + var co = $(o._containment).offset(); + + o.containment = [ + co.left, + co.top, + co.left+(ce.offsetWidth || ce.scrollWidth), + co.top+(ce.offsetHeight || ce.scrollHeight) + ]; + } + + var c = o.containment; + ui.instance.setContrains( + c[0] - (self.offset.left - self.clickOffset.left), //min left + c[2] - (self.offset.left - self.clickOffset.left), //max left + c[1] - (self.offset.top - self.clickOffset.top), //min top + c[3] - (self.offset.top - self.clickOffset.top) //max top + ); + + } + }); + + $.ui.plugin.add("draggable", "grid", { + drag: function(e, ui) { + var o = ui.options; + var newLeft = ui.instance.originalPosition.left + Math.round((e.pageX - ui.instance._pageX) / o.grid[0]) * o.grid[0]; + var newTop = ui.instance.originalPosition.top + Math.round((e.pageY - ui.instance._pageY) / o.grid[1]) * o.grid[1]; + + ui.instance.position.left = newLeft; + ui.instance.position.top = newTop; + + } + }); + + $.ui.plugin.add("draggable", "axis", { + drag: function(e, ui) { + var o = ui.options; + if(o.constraint) o.axis = o.constraint; //Legacy check + switch (o.axis) { + case 'x' : ui.instance.position.top = ui.instance.originalPosition.top; break; + case 'y' : ui.instance.position.left = ui.instance.originalPosition.left; break; + } + } + }); + + $.ui.plugin.add("draggable", "scroll", { + start: function(e, ui) { + var o = ui.options; + o.scrollSensitivity = o.scrollSensitivity || 20; + o.scrollSpeed = o.scrollSpeed || 20; + + ui.instance.overflowY = function(el) { + do { if(/auto|scroll/.test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-y'))) return el; el = el.parent(); } while (el[0].parentNode); + return $(document); + }(this); + ui.instance.overflowX = function(el) { + do { if(/auto|scroll/.test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-x'))) return el; el = el.parent(); } while (el[0].parentNode); + return $(document); + }(this); + }, + drag: function(e, ui) { + + var o = ui.options; + var i = ui.instance; + + if(i.overflowY[0] != document && i.overflowY[0].tagName != 'HTML') { + if(i.overflowY[0].offsetHeight - (ui.position.top - i.overflowY[0].scrollTop + i.clickOffset.top) < o.scrollSensitivity) + i.overflowY[0].scrollTop = i.overflowY[0].scrollTop + o.scrollSpeed; + if((ui.position.top - i.overflowY[0].scrollTop + i.clickOffset.top) < o.scrollSensitivity) + i.overflowY[0].scrollTop = i.overflowY[0].scrollTop - o.scrollSpeed; + } else { + //$(document.body).append('<p>'+(e.pageY - $(document).scrollTop())+'</p>'); + if(e.pageY - $(document).scrollTop() < o.scrollSensitivity) + $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); + if($(window).height() - (e.pageY - $(document).scrollTop()) < o.scrollSensitivity) + $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + } + + if(i.overflowX[0] != document && i.overflowX[0].tagName != 'HTML') { + if(i.overflowX[0].offsetWidth - (ui.position.left - i.overflowX[0].scrollLeft + i.clickOffset.left) < o.scrollSensitivity) + i.overflowX[0].scrollLeft = i.overflowX[0].scrollLeft + o.scrollSpeed; + if((ui.position.top - i.overflowX[0].scrollLeft + i.clickOffset.left) < o.scrollSensitivity) + i.overflowX[0].scrollLeft = i.overflowX[0].scrollLeft - o.scrollSpeed; + } else { + if(e.pageX - $(document).scrollLeft() < o.scrollSensitivity) + $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); + if($(window).width() - (e.pageX - $(document).scrollLeft()) < o.scrollSensitivity) + $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + } + + ui.instance.recallOffset(e); + + } + }); + + $.ui.plugin.add("draggable", "snap", { + start: function(e, ui) { + + ui.instance.snapElements = []; + $(ui.options.snap === true ? '.ui-draggable' : ui.options.snap).each(function() { + var $t = $(this); var $o = $t.offset(); + if(this != ui.instance.element[0]) ui.instance.snapElements.push({ + item: this, + width: $t.outerWidth(), + height: $t.outerHeight(), + top: $o.top, + left: $o.left + }); + }); + + }, + drag: function(e, ui) { + + var d = ui.options.snapTolerance || 20; + var x1 = ui.absolutePosition.left, x2 = x1 + ui.instance.helperProportions.width, + y1 = ui.absolutePosition.top, y2 = y1 + ui.instance.helperProportions.height; + + for (var i = ui.instance.snapElements.length - 1; i >= 0; i--){ + + var l = ui.instance.snapElements[i].left, r = l + ui.instance.snapElements[i].width, + t = ui.instance.snapElements[i].top, b = t + ui.instance.snapElements[i].height; + + //Yes, I know, this is insane ;) + if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) continue; + + if(ui.options.snapMode != 'inner') { + var ts = Math.abs(t - y2) <= 20; + var bs = Math.abs(b - y1) <= 20; + var ls = Math.abs(l - x2) <= 20; + var rs = Math.abs(r - x1) <= 20; + if(ts) ui.position.top = t - ui.instance.offset.top + ui.instance.clickOffset.top - ui.instance.helperProportions.height; + if(bs) ui.position.top = b - ui.instance.offset.top + ui.instance.clickOffset.top; + if(ls) ui.position.left = l - ui.instance.offset.left + ui.instance.clickOffset.left - ui.instance.helperProportions.width; + if(rs) ui.position.left = r - ui.instance.offset.left + ui.instance.clickOffset.left; + } + + if(ui.options.snapMode != 'outer') { + var ts = Math.abs(t - y1) <= 20; + var bs = Math.abs(b - y2) <= 20; + var ls = Math.abs(l - x1) <= 20; + var rs = Math.abs(r - x2) <= 20; + if(ts) ui.position.top = t - ui.instance.offset.top + ui.instance.clickOffset.top; + if(bs) ui.position.top = b - ui.instance.offset.top + ui.instance.clickOffset.top - ui.instance.helperProportions.height; + if(ls) ui.position.left = l - ui.instance.offset.left + ui.instance.clickOffset.left; + if(rs) ui.position.left = r - ui.instance.offset.left + ui.instance.clickOffset.left - ui.instance.helperProportions.width; + } + + }; + } + }); + + $.ui.plugin.add("draggable", "connectToSortable", { + start: function(e,ui) { + ui.instance.sortable = $.data($(ui.options.connectToSortable)[0], 'sortable'); + ui.instance.sortableOffset = ui.instance.sortable.element.offset(); + ui.instance.sortableOuterWidth = ui.instance.sortable.element.outerWidth(); + ui.instance.sortableOuterHeight = ui.instance.sortable.element.outerHeight(); + if(ui.instance.sortable.options.revert) ui.instance.sortable.shouldRevert = true; + }, + stop: function(e,ui) { + //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper + var inst = ui.instance.sortable; + if(inst.isOver) { + inst.isOver = 0; + ui.instance.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance + inst.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) + if(inst.shouldRevert) inst.options.revert = true; //revert here + inst.stop(e); + inst.options.helper = "original"; + } + }, + drag: function(e,ui) { + //This is handy: We reuse the intersectsWith method for checking if the current draggable helper + //intersects with the sortable container + var inst = ui.instance.sortable; + ui.instance.position.absolute = ui.absolutePosition; //Sorry, this is an ugly API fix + + if(inst.intersectsWith.call(ui.instance, { + left: ui.instance.sortableOffset.left, top: ui.instance.sortableOffset.top, + width: ui.instance.sortableOuterWidth, height: ui.instance.sortableOuterHeight + })) { + //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once + if(!inst.isOver) { + inst.isOver = 1; + + //Cache the width/height of the new helper + var height = inst.options.placeholderElement ? $(inst.options.placeholderElement, $(inst.options.items, inst.element)).innerHeight() : $(inst.options.items, inst.element).innerHeight(); + var width = inst.options.placeholderElement ? $(inst.options.placeholderElement, $(inst.options.items, inst.element)).innerWidth() : $(inst.options.items, inst.element).innerWidth(); + + //Now we fake the start of dragging for the sortable instance, + //by cloning the list group item, appending it to the sortable and using it as inst.currentItem + //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) + inst.currentItem = $(this).clone().appendTo(inst.element); + inst.options.helper = function() { return ui.helper[0]; }; + inst.start(e); + + //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes + inst.clickOffset.top = ui.instance.clickOffset.top; + inst.clickOffset.left = ui.instance.clickOffset.left; + inst.offset.left -= ui.absolutePosition.left - inst.position.absolute.left; + inst.offset.top -= ui.absolutePosition.top - inst.position.absolute.top; + + //Do a nifty little helper animation: Animate it to the portlet's size (just takes the first 'li' element in the sortable now) + inst.helperProportions = { width: width, height: height}; //We have to reset the helper proportions, because we are doing our animation there + ui.helper.animate({ height: height, width: width}, 500); + ui.instance.propagate("toSortable", e); + + } + + //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable + if(inst.currentItem) inst.drag(e); + + } else { + + //If it doesn't intersect with the sortable, and it intersected before, + //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval + if(inst.isOver) { + inst.isOver = 0; + inst.cancelHelperRemoval = true; + inst.options.revert = false; //No revert here + inst.stop(e); + inst.options.helper = "original"; + + //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size + inst.currentItem.remove(); + inst.placeholder.remove(); + + ui.helper.animate({ height: this.innerHeight(), width: this.innerWidth() }, 500); + ui.instance.propagate("fromSortable", e); + } + + }; + } + }) + + //TODO: wrapHelper + +})(jQuery); + diff --git a/vendors/jquery/ui.droppable.js b/vendors/jquery/ui.droppable.js new file mode 100755 index 000000000..9cc8388f1 --- /dev/null +++ b/vendors/jquery/ui.droppable.js @@ -0,0 +1,312 @@ +/* + * jQuery UI Droppable + * + * Copyright (c) 2008 Paul Bakaus + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Droppables + * + * Depends: + * ui.base.js + * ui.draggable.js + * + * Revision: $Id: ui.droppable.js 5198 2008-04-04 13:06:40Z paul.bakaus $ + */ +;(function($) { + + $.fn.extend({ + droppable: function(options) { + var args = Array.prototype.slice.call(arguments, 1); + + return this.each(function() { + if (typeof options == "string") { + var drop = $.data(this, "droppable"); + if(drop) drop[options].apply(drop, args); + + } else if(!$.data(this, "droppable")) + new $.ui.droppable(this, options); + }); + } + }); + + $.ui.droppable = function(element, options) { + + //Initialize needed constants + var instance = this; + this.element = $(element); + $.data(element, "droppable", this); + this.element.addClass("ui-droppable"); + + //Prepare the passed options + var o = this.options = options = $.extend({}, $.ui.droppable.defaults, options); + var accept = o.accept; + o = $.extend(o, { + accept: o.accept && o.accept.constructor == Function ? o.accept : function(d) { + return $(d).is(accept); + } + }); + + $(element).bind("setData.droppable", function(event, key, value){ + o[key] = value; + }).bind("getData.droppable", function(event, key){ + return o[key]; + }).bind('remove', function() { + instance.destroy(); + }); + + //Store the droppable's proportions + this.proportions = { width: this.element.outerWidth(), height: this.element.outerHeight() }; + + // Add the reference and positions to the manager + $.ui.ddmanager.droppables.push({ item: this, over: 0, out: 1 }); + + }; + + $.extend($.ui.droppable, { + defaults: { + disabled: false, + tolerance: 'intersect' + } + }); + + $.extend($.ui.droppable.prototype, { + plugins: {}, + ui: function(c) { + return { + instance: this, + draggable: (c.currentItem || c.element), + helper: c.helper, + position: c.position, + absolutePosition: c.positionAbs, + options: this.options, + element: this.element + }; + }, + destroy: function() { + var drop = $.ui.ddmanager.droppables; + for ( var i = 0; i < drop.length; i++ ) + if ( drop[i].item == this ) + drop.splice(i, 1); + + this.element + .removeClass("ui-droppable ui-droppable-disabled") + .removeData("droppable") + .unbind(".droppable"); + }, + enable: function() { + this.element.removeClass("ui-droppable-disabled"); + this.options.disabled = false; + }, + disable: function() { + this.element.addClass("ui-droppable-disabled"); + this.options.disabled = true; + }, + over: function(e) { + + var draggable = $.ui.ddmanager.current; + if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element + + if (this.options.accept.call(this.element,(draggable.currentItem || draggable.element))) { + $.ui.plugin.call(this, 'over', [e, this.ui(draggable)]); + this.element.triggerHandler("dropover", [e, this.ui(draggable)], this.options.over); + } + + }, + out: function(e) { + + var draggable = $.ui.ddmanager.current; + if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element + + if (this.options.accept.call(this.element,(draggable.currentItem || draggable.element))) { + $.ui.plugin.call(this, 'out', [e, this.ui(draggable)]); + this.element.triggerHandler("dropout", [e, this.ui(draggable)], this.options.out); + } + + }, + drop: function(e,custom) { + + var draggable = custom || $.ui.ddmanager.current; + if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element + + var childrenIntersection = false; + this.element.find(".ui-droppable").each(function() { + var inst = $.data(this, 'droppable'); + if(inst.options.greedy && $.ui.intersect(draggable, { item: inst, offset: inst.element.offset() }, inst.options.tolerance)) { + childrenIntersection = true; return false; + } + }); + if(childrenIntersection) return; + + if(this.options.accept.call(this.element,(draggable.currentItem || draggable.element))) { + $.ui.plugin.call(this, 'drop', [e, this.ui(draggable)]); + this.element.triggerHandler("drop", [e, this.ui(draggable)], this.options.drop); + } + + }, + activate: function(e) { + + var draggable = $.ui.ddmanager.current; + $.ui.plugin.call(this, 'activate', [e, this.ui(draggable)]); + if(draggable) this.element.triggerHandler("dropactivate", [e, this.ui(draggable)], this.options.activate); + + }, + deactivate: function(e) { + + var draggable = $.ui.ddmanager.current; + $.ui.plugin.call(this, 'deactivate', [e, this.ui(draggable)]); + if(draggable) this.element.triggerHandler("dropdeactivate", [e, this.ui(draggable)], this.options.deactivate); + + } + }); + + $.ui.intersect = function(draggable, droppable, toleranceMode) { + + if (!droppable.offset) return false; + + var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width, + y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height; + var l = droppable.offset.left, r = l + droppable.item.proportions.width, + t = droppable.offset.top, b = t + droppable.item.proportions.height; + + switch (toleranceMode) { + case 'fit': + + if(!((y2-(draggable.helperProportions.height/2) > t && y1 < t) || (y1 < b && y2 > b) || (x2 > l && x1 < l) || (x1 < r && x2 > r))) return false; + + if(y2-(draggable.helperProportions.height/2) > t && y1 < t) return 1; //Crosses top edge + if(y1 < b && y2 > b) return 2; //Crosses bottom edge + if(x2 > l && x1 < l) return 1; //Crosses left edge + if(x1 < r && x2 > r) return 2; //Crosses right edge + + //return ( l < x1 && x2 < r + // && t < y1 && y2 < b); + break; + case 'intersect': + return ( l < x1 + (draggable.helperProportions.width / 2) // Right Half + && x2 - (draggable.helperProportions.width / 2) < r // Left Half + && t < y1 + (draggable.helperProportions.height / 2) // Bottom Half + && y2 - (draggable.helperProportions.height / 2) < b ); // Top Half + break; + case 'pointer': + return ( l < ((draggable.positionAbs || draggable.position.absolute).left + draggable.clickOffset.left) && ((draggable.positionAbs || draggable.position.absolute).left + draggable.clickOffset.left) < r + && t < ((draggable.positionAbs || draggable.position.absolute).top + draggable.clickOffset.top) && ((draggable.positionAbs || draggable.position.absolute).top + draggable.clickOffset.top) < b); + break; + case 'touch': + return ( (y1 >= t && y1 <= b) || // Top edge touching + (y2 >= t && y2 <= b) || // Bottom edge touching + (y1 < t && y2 > b) // Surrounded vertically + ) && ( + (x1 >= l && x1 <= r) || // Left edge touching + (x2 >= l && x2 <= r) || // Right edge touching + (x1 < l && x2 > r) // Surrounded horizontally + ); + break; + default: + return false; + break; + } + + }; + + /* + This manager tracks offsets of draggables and droppables + */ + $.ui.ddmanager = { + current: null, + droppables: [], + prepareOffsets: function(t, e) { + + var m = $.ui.ddmanager.droppables; + var type = e ? e.type : null; // workaround for #2317 + for (var i = 0; i < m.length; i++) { + + if(m[i].item.options.disabled || (t && !m[i].item.options.accept.call(m[i].item.element,(t.currentItem || t.element)))) continue; + m[i].offset = $(m[i].item.element).offset(); + m[i].item.proportions = { width: m[i].item.element.outerWidth(), height: m[i].item.element.outerHeight() }; + + if(type == "dragstart") m[i].item.activate.call(m[i].item, e); //Activate the droppable if used directly from draggables + } + + }, + drop: function(draggable, e) { + + $.each($.ui.ddmanager.droppables, function() { + + if (!this.item.options.disabled && $.ui.intersect(draggable, this, this.item.options.tolerance)) + this.item.drop.call(this.item, e); + + if (!this.item.options.disabled && this.item.options.accept.call(this.item.element,(draggable.currentItem || draggable.element))) { + this.out = 1; this.over = 0; + this.item.deactivate.call(this.item, e); + } + + }); + + }, + drag: function(draggable, e) { + + //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. + if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, e); + + //Run through all droppables and check their positions based on specific tolerance options + $.each($.ui.ddmanager.droppables, function() { + + if(this.item.disabled || this.greedyChild) return; + var intersects = $.ui.intersect(draggable, this, this.item.options.tolerance); + + var c = !intersects && this.over == 1 ? 'out' : (intersects && this.over == 0 ? 'over' : null); + if(!c) return; + + var instance = $.data(this.item.element[0], 'droppable'); + if (instance.options.greedy) { + this.item.element.parents('.ui-droppable:eq(0)').each(function() { + var parent = this; + $.each($.ui.ddmanager.droppables, function() { + if (this.item.element[0] != parent) return; + this[c] = 0; + this[c == 'out' ? 'over' : 'out'] = 1; + this.greedyChild = (c == 'over' ? 1 : 0); + this.item[c == 'out' ? 'over' : 'out'].call(this.item, e); + return false; + }); + }); + } + + this[c] = 1; this[c == 'out' ? 'over' : 'out'] = 0; + this.item[c].call(this.item, e); + + }); + + } + }; + +/* + * Droppable Extensions + */ + + $.ui.plugin.add("droppable", "activeClass", { + activate: function(e, ui) { + $(this).addClass(ui.options.activeClass); + }, + deactivate: function(e, ui) { + $(this).removeClass(ui.options.activeClass); + }, + drop: function(e, ui) { + $(this).removeClass(ui.options.activeClass); + } + }); + + $.ui.plugin.add("droppable", "hoverClass", { + over: function(e, ui) { + $(this).addClass(ui.options.hoverClass); + }, + out: function(e, ui) { + $(this).removeClass(ui.options.hoverClass); + }, + drop: function(e, ui) { + $(this).removeClass(ui.options.hoverClass); + } + }); + +})(jQuery); diff --git a/vendors/jquery/ui.sortable.js b/vendors/jquery/ui.sortable.js new file mode 100755 index 000000000..b0f7929f3 --- /dev/null +++ b/vendors/jquery/ui.sortable.js @@ -0,0 +1,676 @@ +/* + * jQuery UI Sortable + * + * Copyright (c) 2008 Paul Bakaus + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Sortables + * + * Depends: + * ui.base.js + * + * Revision: $Id: ui.sortable.js 5199 2008-04-04 14:04:32Z paul.bakaus $ + */ +;(function($) { + + if (window.Node && Node.prototype && !Node.prototype.contains) { + Node.prototype.contains = function (arg) { + return !!(this.compareDocumentPosition(arg) & 16); + }; + } + + $.fn.extend({ + sortable: function(options) { + + var args = Array.prototype.slice.call(arguments, 1); + + if (options == "serialize" || options == "toArray") + return $.data(this[0], "sortable")[options](arguments[1]); + + return this.each(function() { + if (typeof options == "string") { + var sort = $.data(this, "sortable"); + if (sort) sort[options].apply(sort, args); + + } else if(!$.data(this, "sortable")) + new $.ui.sortable(this, options); + }); + } + }); + + $.ui.sortable = function(element, options) { + //Initialize needed constants + var self = this; + + this.element = $(element); + this.containerCache = {}; + + $.data(element, "sortable", this); + this.element.addClass("ui-sortable"); + + //Prepare the passed options + this.options = $.extend({}, options); + var o = this.options; + $.extend(o, { + items: this.options.items || '> *', + zIndex: this.options.zIndex || 1000, + startCondition: function() { + return !self.options.disabled; + } + }); + + $(element).bind("setData.sortable", function(event, key, value){ + self.options[key] = value; + }).bind("getData.sortable", function(event, key){ + return self.options[key]; + }); + + //Get the items + this.refresh(); + + //Let's determine if the items are floating + this.floating = this.items.length ? (/left|right/).test(this.items[0].item.css('float')) : false; + + //Let's determine the parent's offset + if(!(/(relative|absolute|fixed)/).test(this.element.css('position'))) this.element.css('position', 'relative'); + this.offset = this.element.offset(); + + //Initialize mouse events for interaction + this.element.mouseInteraction({ + executor: this, + delay: o.delay, + distance: o.distance || 0, + dragPrevention: o.prevention ? o.prevention.toLowerCase().split(',') : ['input','textarea','button','select','option'], + start: this.start, + stop: this.stop, + drag: this.drag, + condition: function(e) { + + if(this.options.disabled || this.options.type == 'static') return false; + + //Find out if the clicked node (or one of its parents) is a actual item in this.items + var currentItem = null, nodes = $(e.target).parents().each(function() { + if($.data(this, 'sortable-item')) { + currentItem = $(this); + return false; + } + }); + if($.data(e.target, 'sortable-item')) currentItem = $(e.target); + + if(!currentItem) return false; + if(this.options.handle) { + var validHandle = false; + $(this.options.handle, currentItem).each(function() { if(this == e.target) validHandle = true; }); + if(!validHandle) return false; + } + + this.currentItem = currentItem; + return true; + + } + }); + + //Prepare cursorAt + if(o.cursorAt && o.cursorAt.constructor == Array) + o.cursorAt = { left: o.cursorAt[0], top: o.cursorAt[1] }; + }; + + $.extend($.ui.sortable.prototype, { + plugins: {}, + ui: function(inst) { + return { + helper: (inst || this)["helper"], + placeholder: (inst || this)["placeholder"] || $([]), + position: (inst || this)["position"].current, + absolutePosition: (inst || this)["position"].absolute, + instance: this, + options: this.options, + element: this.element, + item: (inst || this)["currentItem"], + sender: inst ? inst.element : null + }; + }, + propagate: function(n,e,inst) { + $.ui.plugin.call(this, n, [e, this.ui(inst)]); + this.element.triggerHandler(n == "sort" ? n : "sort"+n, [e, this.ui(inst)], this.options[n]); + }, + serialize: function(o) { + + var items = $(this.options.items, this.element).not('.ui-sortable-helper'); //Only the items of the sortable itself + var str = []; o = o || {}; + + items.each(function() { + var res = ($(this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/)); + if(res) str.push((o.key || res[1])+'[]='+(o.key ? res[1] : res[2])); + }); + + return str.join('&'); + + }, + toArray: function(attr) { + var items = $(this.options.items, this.element).not('.ui-sortable-helper'); //Only the items of the sortable itself + var ret = []; + + items.each(function() { ret.push($(this).attr(attr || 'id')); }); + return ret; + }, + enable: function() { + this.element.removeClass("ui-sortable-disabled"); + this.options.disabled = false; + }, + disable: function() { + this.element.addClass("ui-sortable-disabled"); + this.options.disabled = true; + }, + /* Be careful with the following core functions */ + intersectsWith: function(item) { + + var x1 = this.position.absolute.left, x2 = x1 + this.helperProportions.width, + y1 = this.position.absolute.top, y2 = y1 + this.helperProportions.height; + var l = item.left, r = l + item.width, + t = item.top, b = t + item.height; + + return ( l < x1 + (this.helperProportions.width / 2) // Right Half + && x2 - (this.helperProportions.width / 2) < r // Left Half + && t < y1 + (this.helperProportions.height / 2) // Bottom Half + && y2 - (this.helperProportions.height / 2) < b ); // Top Half + + }, + intersectsWithEdge: function(item) { + var x1 = this.position.absolute.left, x2 = x1 + this.helperProportions.width, + y1 = this.position.absolute.top, y2 = y1 + this.helperProportions.height; + var l = item.left, r = l + item.width, + t = item.top, b = t + item.height; + + + if (!( l < x1 + (this.helperProportions.width / 2) // Right Half + && x2 - (this.helperProportions.width / 2) < r // Left Half + && t < y1 + (this.helperProportions.height / 2) // Bottom Half + && y2 - (this.helperProportions.height / 2) < b )) return false; // Top Half + + if(this.floating) { + if(x2 > l && x1 < l) return 2; //Crosses left edge + if(x1 < r && x2 > r) return 1; //Crosses right edge + } else { + if(y2 > t && y1 < t) return 1; //Crosses top edge + if(y1 < b && y2 > b) return 2; //Crosses bottom edge + } + + return false; + + }, + //This method checks approximately if the item is dragged in a container, but doesn't touch any items + inEmptyZone: function(container) { + + if(!$(container.options.items, container.element).length) { + return container.options.dropOnEmpty ? true : false; + }; + + var last = $(container.options.items, container.element).not('.ui-sortable-helper'); last = $(last[last.length-1]); + var top = last.offset()[this.floating ? 'left' : 'top'] + last[0][this.floating ? 'offsetWidth' : 'offsetHeight']; + return (this.position.absolute[this.floating ? 'left' : 'top'] > top); + }, + refresh: function() { + this.refreshItems(); + this.refreshPositions(); + }, + refreshItems: function() { + + this.items = []; + this.containers = [this]; + var items = this.items; + var queries = [$(this.options.items, this.element)]; + + if(this.options.connectWith) { + for (var i = this.options.connectWith.length - 1; i >= 0; i--){ + var cur = $(this.options.connectWith[i]); + for (var j = cur.length - 1; j >= 0; j--){ + var inst = $.data(cur[j], 'sortable'); + if(inst && !inst.options.disabled) { + queries.push($(inst.options.items, inst.element)); + this.containers.push(inst); + } + }; + }; + } + + for (var i = queries.length - 1; i >= 0; i--){ + queries[i].each(function() { + $.data(this, 'sortable-item', true); // Data for target checking (mouse manager) + items.push({ + item: $(this), + width: 0, height: 0, + left: 0, top: 0 + }); + }); + }; + + }, + refreshPositions: function(fast) { + for (var i = this.items.length - 1; i >= 0; i--){ + if(!fast) this.items[i].width = this.items[i].item.outerWidth(); + if(!fast) this.items[i].height = this.items[i].item.outerHeight(); + var p = this.items[i].item.offset(); + this.items[i].left = p.left; + this.items[i].top = p.top; + }; + for (var i = this.containers.length - 1; i >= 0; i--){ + var p =this.containers[i].element.offset(); + this.containers[i].containerCache.left = p.left; + this.containers[i].containerCache.top = p.top; + this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); + this.containers[i].containerCache.height= this.containers[i].element.outerHeight(); + }; + }, + destroy: function() { + this.element + .removeClass("ui-sortable ui-sortable-disabled") + .removeData("sortable") + .unbind(".sortable") + .removeMouseInteraction(); + + for ( var i = this.items.length - 1; i >= 0; i-- ) + this.items[i].item.removeData("sortable-item"); + }, + createPlaceholder: function(that) { + (that || this).placeholderElement = this.options.placeholderElement ? $(this.options.placeholderElement, (that || this).currentItem) : (that || this).currentItem; + (that || this).placeholder = $('<div></div>') + .addClass(this.options.placeholder) + .appendTo('body') + .css({ position: 'absolute' }) + .css((that || this).placeholderElement.offset()) + .css({ width: (that || this).placeholderElement.outerWidth(), height: (that || this).placeholderElement.outerHeight() }) + ; + }, + contactContainers: function(e) { + for (var i = this.containers.length - 1; i >= 0; i--){ + + if(this.intersectsWith(this.containers[i].containerCache)) { + if(!this.containers[i].containerCache.over) { + + + if(this.currentContainer != this.containers[i]) { + + //When entering a new container, we will find the item with the least distance and append our item near it + var dist = 10000; var itemWithLeastDistance = null; var base = this.position.absolute[this.containers[i].floating ? 'left' : 'top']; + for (var j = this.items.length - 1; j >= 0; j--) { + if(!this.containers[i].element[0].contains(this.items[j].item[0])) continue; + var cur = this.items[j][this.containers[i].floating ? 'left' : 'top']; + if(Math.abs(cur - base) < dist) { + dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; + } + } + + //We also need to exchange the placeholder + if(this.placeholder) this.placeholder.remove(); + if(this.containers[i].options.placeholder) { + this.containers[i].createPlaceholder(this); + } else { + this.placeholder = null; this.placeholderElement = null; + } + + + itemWithLeastDistance ? this.rearrange(e, itemWithLeastDistance) : this.rearrange(e, null, this.containers[i].element); + this.propagate("change", e); //Call plugins and callbacks + this.containers[i].propagate("change", e, this); //Call plugins and callbacks + this.currentContainer = this.containers[i]; + + } + + this.containers[i].propagate("over", e, this); + this.containers[i].containerCache.over = 1; + } + } else { + if(this.containers[i].containerCache.over) { + this.containers[i].propagate("out", e, this); + this.containers[i].containerCache.over = 0; + } + } + + }; + }, + start: function(e,el) { + + var o = this.options; + this.refresh(); + + //Create and append the visible helper + this.helper = typeof o.helper == 'function' ? $(o.helper.apply(this.element[0], [e, this.currentItem])) : this.currentItem.clone(); + if(!this.helper.parents('body').length) this.helper.appendTo(o.appendTo || this.currentItem[0].parentNode); //Add the helper to the DOM if that didn't happen already + this.helper.css({ position: 'absolute', clear: 'both' }).addClass('ui-sortable-helper'); //Position it absolutely and add a helper class + + //Prepare variables for position generation + $.extend(this, { + offsetParent: this.helper.offsetParent(), + offsets: { + absolute: this.currentItem.offset() + }, + mouse: { + start: { top: e.pageY, left: e.pageX } + }, + margins: { + top: parseInt(this.currentItem.css("marginTop")) || 0, + left: parseInt(this.currentItem.css("marginLeft")) || 0 + } + }); + + //The relative click offset + this.offsets.parent = this.offsetParent.offset(); + this.clickOffset = { left: e.pageX - this.offsets.absolute.left, top: e.pageY - this.offsets.absolute.top }; + + this.originalPosition = { + left: this.offsets.absolute.left - this.offsets.parent.left - this.margins.left, + top: this.offsets.absolute.top - this.offsets.parent.top - this.margins.top + } + + //Generate a flexible offset that will later be subtracted from e.pageX/Y + //I hate margins - they need to be removed before positioning the element absolutely.. + this.offset = { + left: e.pageX - this.originalPosition.left, + top: e.pageY - this.originalPosition.top + }; + + //Save the first time position + $.extend(this, { + position: { + current: { top: e.pageY - this.offset.top, left: e.pageX - this.offset.left }, + absolute: { left: e.pageX - this.clickOffset.left, top: e.pageY - this.clickOffset.top }, + dom: this.currentItem.prev()[0] + } + }); + + //If o.placeholder is used, create a new element at the given position with the class + if(o.placeholder) this.createPlaceholder(); + + this.propagate("start", e); //Call plugins and callbacks + this.helperProportions = { width: this.helper.outerWidth(), height: this.helper.outerHeight() }; //Save and store the helper proportions + + //If we have something in cursorAt, we'll use it + if(o.cursorAt) { + if(o.cursorAt.top != undefined || o.cursorAt.bottom != undefined) { + this.offset.top -= this.clickOffset.top - (o.cursorAt.top != undefined ? o.cursorAt.top : (this.helperProportions.height - o.cursorAt.bottom)); + this.clickOffset.top = (o.cursorAt.top != undefined ? o.cursorAt.top : (this.helperProportions.height - o.cursorAt.bottom)); + } + if(o.cursorAt.left != undefined || o.cursorAt.right != undefined) { + this.offset.left -= this.clickOffset.left - (o.cursorAt.left != undefined ? o.cursorAt.left : (this.helperProportions.width - o.cursorAt.right)); + this.clickOffset.left = (o.cursorAt.left != undefined ? o.cursorAt.left : (this.helperProportions.width - o.cursorAt.right)); + } + } + + if(this.options.placeholder != 'clone') $(this.currentItem).css('visibility', 'hidden'); //Set the original element visibility to hidden to still fill out the white space + for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i].propagate("activate", e, this); } //Post 'activate' events to possible containers + + //Prepare possible droppables + if($.ui.ddmanager) $.ui.ddmanager.current = this; + if ($.ui.ddmanager && !o.dropBehaviour) $.ui.ddmanager.prepareOffsets(this, e); + + this.dragging = true; + return false; + + }, + stop: function(e) { + + this.propagate("stop", e); //Call plugins and trigger callbacks + if(this.position.dom != this.currentItem.prev()[0]) this.propagate("update", e); //Trigger update callback if the DOM position has changed + if(!this.element[0].contains(this.currentItem[0])) { //Node was moved out of the current element + this.propagate("remove", e); + for (var i = this.containers.length - 1; i >= 0; i--){ + if(this.containers[i].element[0].contains(this.currentItem[0])) { + this.containers[i].propagate("update", e, this); + this.containers[i].propagate("receive", e, this); + } + }; + }; + + //Post events to containers + for (var i = this.containers.length - 1; i >= 0; i--){ + this.containers[i].propagate("deactivate", e, this); + if(this.containers[i].containerCache.over) { + this.containers[i].propagate("out", e, this); + this.containers[i].containerCache.over = 0; + } + } + + //If we are using droppables, inform the manager about the drop + if ($.ui.ddmanager && !this.options.dropBehaviour) $.ui.ddmanager.drop(this, e); + + this.dragging = false; + if(this.cancelHelperRemoval) return false; + $(this.currentItem).css('visibility', ''); + if(this.placeholder) this.placeholder.remove(); + this.helper.remove(); + + return false; + + }, + drag: function(e) { + + //Compute the helpers position + this.position.current = { top: e.pageY - this.offset.top, left: e.pageX - this.offset.left }; + this.position.absolute = { left: e.pageX - this.clickOffset.left, top: e.pageY - this.clickOffset.top }; + + //Rearrange + for (var i = this.items.length - 1; i >= 0; i--) { + var intersection = this.intersectsWithEdge(this.items[i]); + if(!intersection) continue; + + if( this.items[i].item[0] != this.currentItem[0] //cannot intersect with itself + && this.currentItem[intersection == 1 ? "next" : "prev"]()[0] != this.items[i].item[0] //no useless actions that have been done before + && !this.currentItem[0].contains(this.items[i].item[0]) //no action if the item moved is the parent of the item checked + && (this.options.type == 'semi-dynamic' ? !this.element[0].contains(this.items[i].item[0]) : true) + ) { + + this.direction = intersection == 1 ? "down" : "up"; + this.rearrange(e, this.items[i]); + this.propagate("change", e); //Call plugins and callbacks + break; + } + } + + //Post events to containers + this.contactContainers(e); + + //Interconnect with droppables + if($.ui.ddmanager) $.ui.ddmanager.drag(this, e); + + this.propagate("sort", e); //Call plugins and callbacks + this.helper.css({ left: this.position.current.left+'px', top: this.position.current.top+'px' }); // Stick the helper to the cursor + return false; + + }, + rearrange: function(e, i, a) { + a ? a.append(this.currentItem) : i.item[this.direction == 'down' ? 'before' : 'after'](this.currentItem); + this.refreshPositions(true); //Precompute after each DOM insertion, NOT on mousemove + if(this.placeholderElement) this.placeholder.css(this.placeholderElement.offset()); + } + }); + +/* + * Sortable Extensions + */ + + $.ui.plugin.add("sortable", "cursor", { + start: function(e, ui) { + var t = $('body'); + if (t.css("cursor")) ui.options._cursor = t.css("cursor"); + t.css("cursor", ui.options.cursor); + }, + stop: function(e, ui) { + if (ui.options._cursor) $('body').css("cursor", ui.options._cursor); + } + }); + + $.ui.plugin.add("sortable", "zIndex", { + start: function(e, ui) { + var t = ui.helper; + if(t.css("zIndex")) ui.options._zIndex = t.css("zIndex"); + t.css('zIndex', ui.options.zIndex); + }, + stop: function(e, ui) { + if(ui.options._zIndex) $(ui.helper).css('zIndex', ui.options._zIndex); + } + }); + + $.ui.plugin.add("sortable", "opacity", { + start: function(e, ui) { + var t = ui.helper; + if(t.css("opacity")) ui.options._opacity = t.css("opacity"); + t.css('opacity', ui.options.opacity); + }, + stop: function(e, ui) { + if(ui.options._opacity) $(ui.helper).css('opacity', ui.options._opacity); + } + }); + + + $.ui.plugin.add("sortable", "revert", { + stop: function(e, ui) { + var self = ui.instance; + self.cancelHelperRemoval = true; + var cur = self.currentItem.offset(); + var op = self.helper.offsetParent().offset(); + if(ui.instance.options.zIndex) ui.helper.css('zIndex', ui.instance.options.zIndex); //Do the zIndex again because it already was resetted by the plugin above on stop + + //Also animate the placeholder if we have one + if(ui.instance.placeholder) ui.instance.placeholder.animate({ opacity: 'hide' }, parseInt(ui.options.revert, 10) || 500); + + + ui.helper.animate({ + left: cur.left - op.left - self.margins.left, + top: cur.top - op.top - self.margins.top + }, parseInt(ui.options.revert, 10) || 500, function() { + self.currentItem.css('visibility', 'visible'); + window.setTimeout(function() { + if(self.placeholder) self.placeholder.remove(); + self.helper.remove(); + if(ui.options._zIndex) ui.helper.css('zIndex', ui.options._zIndex); + }, 50); + }); + } + }); + + + $.ui.plugin.add("sortable", "containment", { + start: function(e, ui) { + + var o = ui.options; + if((o.containment.left != undefined || o.containment.constructor == Array) && !o._containment) return; + if(!o._containment) o._containment = o.containment; + + if(o._containment == 'parent') o._containment = this[0].parentNode; + if(o._containment == 'sortable') o._containment = this[0]; + if(o._containment == 'document') { + o.containment = [ + 0, + 0, + $(document).width(), + ($(document).height() || document.body.parentNode.scrollHeight) + ]; + } else { //I'm a node, so compute top/left/right/bottom + + var ce = $(o._containment); + var co = ce.offset(); + + o.containment = [ + co.left, + co.top, + co.left+(ce.outerWidth() || ce[0].scrollWidth), + co.top+(ce.outerHeight() || ce[0].scrollHeight) + ]; + } + + }, + sort: function(e, ui) { + + var o = ui.options; + var h = ui.helper; + var c = o.containment; + var self = ui.instance; + var borderLeft = (parseInt(self.offsetParent.css("borderLeftWidth"), 10) || 0); + var borderRight = (parseInt(self.offsetParent.css("borderRightWidth"), 10) || 0); + var borderTop = (parseInt(self.offsetParent.css("borderTopWidth"), 10) || 0); + var borderBottom = (parseInt(self.offsetParent.css("borderBottomWidth"), 10) || 0); + + if(c.constructor == Array) { + if((self.position.absolute.left < c[0])) self.position.current.left = c[0] - self.offsets.parent.left - self.margins.left; + if((self.position.absolute.top < c[1])) self.position.current.top = c[1] - self.offsets.parent.top - self.margins.top; + if(self.position.absolute.left - c[2] + self.helperProportions.width >= 0) self.position.current.left = c[2] - self.offsets.parent.left - self.helperProportions.width - self.margins.left - borderLeft - borderRight; + if(self.position.absolute.top - c[3] + self.helperProportions.height >= 0) self.position.current.top = c[3] - self.offsets.parent.top - self.helperProportions.height - self.margins.top - borderTop - borderBottom; + } else { + if((ui.position.left < c.left)) self.position.current.left = c.left; + if((ui.position.top < c.top)) self.position.current.top = c.top; + if(ui.position.left - self.offsetParent.innerWidth() + self.helperProportions.width + c.right + borderLeft + borderRight >= 0) self.position.current.left = self.offsetParent.innerWidth() - self.helperProportions.width - c.right - borderLeft - borderRight; + if(ui.position.top - self.offsetParent.innerHeight() + self.helperProportions.height + c.bottom + borderTop + borderBottom >= 0) self.position.current.top = self.offsetParent.innerHeight() - self.helperProportions.height - c.bottom - borderTop - borderBottom; + } + + } + }); + + $.ui.plugin.add("sortable", "axis", { + sort: function(e, ui) { + var o = ui.options; + if(o.constraint) o.axis = o.constraint; //Legacy check + o.axis == 'x' ? ui.instance.position.top = ui.instance.originalPosition.top : ui.instance.position.left = ui.instance.originalPosition.left; + } + }); + + $.ui.plugin.add("sortable", "scroll", { + start: function(e, ui) { + var o = ui.options; + o.scrollSensitivity = o.scrollSensitivity || 20; + o.scrollSpeed = o.scrollSpeed || 20; + + ui.instance.overflowY = function(el) { + do { if((/auto|scroll/).test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-y'))) return el; el = el.parent(); } while (el[0].parentNode); + return $(document); + }(this); + ui.instance.overflowX = function(el) { + do { if((/auto|scroll/).test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-x'))) return el; el = el.parent(); } while (el[0].parentNode); + return $(document); + }(this); + + if(ui.instance.overflowY[0] != document && ui.instance.overflowY[0].tagName != 'HTML') ui.instance.overflowYstart = ui.instance.overflowY[0].scrollTop; + if(ui.instance.overflowX[0] != document && ui.instance.overflowX[0].tagName != 'HTML') ui.instance.overflowXstart = ui.instance.overflowX[0].scrollLeft; + + }, + sort: function(e, ui) { + + var o = ui.options; + var i = ui.instance; + + if(i.overflowY[0] != document && i.overflowY[0].tagName != 'HTML') { + if(i.overflowY[0].offsetHeight - (ui.position.top - i.overflowY[0].scrollTop + i.clickOffset.top) < o.scrollSensitivity) + i.overflowY[0].scrollTop = i.overflowY[0].scrollTop + o.scrollSpeed; + if((ui.position.top - i.overflowY[0].scrollTop + i.clickOffset.top) < o.scrollSensitivity) + i.overflowY[0].scrollTop = i.overflowY[0].scrollTop - o.scrollSpeed; + } else { + //$(document.body).append('<p>'+(e.pageY - $(document).scrollTop())+'</p>'); + if(e.pageY - $(document).scrollTop() < o.scrollSensitivity) + $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); + if($(window).height() - (e.pageY - $(document).scrollTop()) < o.scrollSensitivity) + $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + } + + if(i.overflowX[0] != document && i.overflowX[0].tagName != 'HTML') { + if(i.overflowX[0].offsetWidth - (ui.position.left - i.overflowX[0].scrollLeft + i.clickOffset.left) < o.scrollSensitivity) + i.overflowX[0].scrollLeft = i.overflowX[0].scrollLeft + o.scrollSpeed; + if((ui.position.top - i.overflowX[0].scrollLeft + i.clickOffset.left) < o.scrollSensitivity) + i.overflowX[0].scrollLeft = i.overflowX[0].scrollLeft - o.scrollSpeed; + } else { + if(e.pageX - $(document).scrollLeft() < o.scrollSensitivity) + $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); + if($(window).width() - (e.pageX - $(document).scrollLeft()) < o.scrollSensitivity) + $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + } + + //ui.instance.recallOffset(e); + i.offset = { + left: i.mouse.start.left - i.originalPosition.left + (i.overflowXstart !== undefined ? i.overflowXstart - i.overflowX[0].scrollLeft : 0), + top: i.mouse.start.top - i.originalPosition.top + (i.overflowYstart !== undefined ? i.overflowYstart - i.overflowX[0].scrollTop : 0) + }; + + } + }); + +})(jQuery); |