[SPIP] +2.1.12
[velocampus/web/www.git] / www / plugins / auto / spip-bonux / formulaires / selecteur / jquery-ui-1.6.custom.js
diff --git a/www/plugins/auto/spip-bonux/formulaires/selecteur/jquery-ui-1.6.custom.js b/www/plugins/auto/spip-bonux/formulaires/selecteur/jquery-ui-1.6.custom.js
new file mode 100644 (file)
index 0000000..dbec79f
--- /dev/null
@@ -0,0 +1,2255 @@
+/*
+ * jQuery UI 1.6
+ *
+ * Copyright (c) 2008 AUTHORS.txt (http://ui.jquery.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI
+ */
+;(function($) {
+
+var _remove = $.fn.remove,
+       isFF2 = $.browser.mozilla && (parseFloat($.browser.version) < 1.9);
+
+//Helper functions and ui object
+$.ui = {
+
+       version: "1.6",
+
+       // $.ui.plugin is deprecated.  Use the proxy pattern instead.
+       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, args) {
+                       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, args);
+                               }
+                       }
+               }
+       },
+
+       contains: function(a, b) {
+               var safari2 = $.browser.safari && $.browser.version < 522;
+           if (a.contains && !safari2) {
+               return a.contains(b);
+           }
+           if (a.compareDocumentPosition)
+               return !!(a.compareDocumentPosition(b) & 16);
+           while (b = b.parentNode)
+                 if (b == a) return true;
+           return false;
+       },
+
+       cssCache: {},
+       css: function(name) {
+               if ($.ui.cssCache[name]) { return $.ui.cssCache[name]; }
+               var tmp = $('<div class="ui-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];
+       },
+
+       hasScroll: function(el, a) {
+
+               //If overflow is hidden, the element might have extra content, but the user wants to hide it
+               if ($(el).css('overflow') == 'hidden') { return false; }
+
+               var scroll = (a && a == 'left') ? 'scrollLeft' : 'scrollTop',
+                       has = false;
+
+               if (el[scroll] > 0) { return true; }
+
+               // TODO: determine which cases actually cause this to happen
+               // if the element doesn't have the scroll set, see if it's possible to
+               // set the scroll
+               el[scroll] = 1;
+               has = (el[scroll] > 0);
+               el[scroll] = 0;
+               return has;
+       },
+
+       isOverAxis: function(x, reference, size) {
+               //Determines when x coordinate is over "b" element axis
+               return (x > reference) && (x < (reference + size));
+       },
+
+       isOver: function(y, x, top, left, height, width) {
+               //Determines when x, y coordinates is over "b" element
+               return $.ui.isOverAxis(y, top, height) && $.ui.isOverAxis(x, left, width);
+       },
+
+       keyCode: {
+               BACKSPACE: 8,
+               CAPS_LOCK: 20,
+               COMMA: 188,
+               CONTROL: 17,
+               DELETE: 46,
+               DOWN: 40,
+               END: 35,
+               ENTER: 13,
+               ESCAPE: 27,
+               HOME: 36,
+               INSERT: 45,
+               LEFT: 37,
+               NUMPAD_ADD: 107,
+               NUMPAD_DECIMAL: 110,
+               NUMPAD_DIVIDE: 111,
+               NUMPAD_ENTER: 108,
+               NUMPAD_MULTIPLY: 106,
+               NUMPAD_SUBTRACT: 109,
+               PAGE_DOWN: 34,
+               PAGE_UP: 33,
+               PERIOD: 190,
+               RIGHT: 39,
+               SHIFT: 16,
+               SPACE: 32,
+               TAB: 9,
+               UP: 38
+       }
+
+};
+
+// WAI-ARIA normalization
+if (isFF2) {
+       var attr = $.attr,
+               removeAttr = $.fn.removeAttr,
+               ariaNS = "http://www.w3.org/2005/07/aaa",
+               ariaState = /^aria-/,
+               ariaRole = /^wairole:/;
+
+       $.attr = function(elem, name, value) {
+               var set = value !== undefined;
+
+               return (name == 'role'
+                       ? (set
+                               ? attr.call(this, elem, name, "wairole:" + value)
+                               : (attr.apply(this, arguments) || "").replace(ariaRole, ""))
+                       : (ariaState.test(name)
+                               ? (set
+                                       ? elem.setAttributeNS(ariaNS,
+                                               name.replace(ariaState, "aaa:"), value)
+                                       : attr.call(this, elem, name.replace(ariaState, "aaa:")))
+                               : attr.apply(this, arguments)));
+       };
+
+       $.fn.removeAttr = function(name) {
+               return (ariaState.test(name)
+                       ? this.each(function() {
+                               this.removeAttributeNS(ariaNS, name.replace(ariaState, ""));
+                       }) : removeAttr.call(this, name));
+       };
+}
+
+//jQuery plugins
+$.fn.extend({
+
+       remove: function() {
+               // Safari has a native remove event which actually removes DOM elements,
+               // so we have to use triggerHandler instead of trigger (#3037).
+               $("*", this).add(this).each(function() {
+                       $(this).triggerHandler("remove");
+               });
+               return _remove.apply(this, arguments );
+       },
+
+       enableSelection: function() {
+               return this
+                       .attr('unselectable', 'off')
+                       .css('MozUserSelect', '')
+                       .unbind('selectstart.ui');
+       },
+
+       disableSelection: function() {
+               return this
+                       .attr('unselectable', 'on')
+                       .css('MozUserSelect', 'none')
+                       .bind('selectstart.ui', function() { return false; });
+       },
+
+       scrollParent: function() {
+
+               var scrollParent;
+               if(($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) {
+                       scrollParent = this.parents().filter(function() {
+                               return (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1)) && (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
+                       }).eq(0);
+               } else {
+                       scrollParent = this.parents().filter(function() {
+                               return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
+                       }).eq(0);
+               }
+
+               return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent;
+
+
+       }
+
+});
+
+
+//Additional selectors
+$.extend($.expr[':'], {
+
+       data: function(a, i, m) {
+               return $.data(a, m[3]);
+       },
+
+       // TODO: add support for object, area
+       tabbable: function(a, i, m) {
+
+               var nodeName = a.nodeName.toLowerCase();
+               function isVisible(element) {
+                       return !($(element).is(':hidden') || $(element).parents(':hidden').length);
+               }
+
+               return (
+                       // in tab order
+                       a.tabIndex >= 0 &&
+
+                       ( // filter node types that participate in the tab order
+
+                               // anchor tag
+                               ('a' == nodeName && a.href) ||
+
+                               // enabled form element
+                               (/input|select|textarea|button/.test(nodeName) &&
+                                       'hidden' != a.type && !a.disabled)
+                       ) &&
+
+                       // visible on page
+                       isVisible(a)
+               );
+
+       }
+
+});
+
+
+// $.widget is a factory to create jQuery plugins
+// taking some boilerplate code out of the plugin code
+function getter(namespace, plugin, method, args) {
+       function getMethods(type) {
+               var methods = $[namespace][plugin][type] || [];
+               return (typeof methods == 'string' ? methods.split(/,?\s+/) : methods);
+       }
+
+       var methods = getMethods('getter');
+       if (args.length == 1 && typeof args[0] == 'string') {
+               methods = methods.concat(getMethods('getterSetter'));
+       }
+       return ($.inArray(method, methods) != -1);
+}
+
+$.widget = function(name, prototype) {
+       var namespace = name.split(".")[0];
+       name = name.split(".")[1];
+
+       // create plugin method
+       $.fn[name] = function(options) {
+               var isMethodCall = (typeof options == 'string'),
+                       args = Array.prototype.slice.call(arguments, 1);
+
+               // prevent calls to internal methods
+               if (isMethodCall && options.substring(0, 1) == '_') {
+                       return this;
+               }
+
+               // handle getter methods
+               if (isMethodCall && getter(namespace, name, options, args)) {
+                       var instance = $.data(this[0], name);
+                       return (instance ? instance[options].apply(instance, args)
+                               : undefined);
+               }
+
+               // handle initialization and non-getter methods
+               return this.each(function() {
+                       var instance = $.data(this, name);
+
+                       // constructor
+                       (!instance && !isMethodCall &&
+                               $.data(this, name, new $[namespace][name](this, options)));
+
+                       // method call
+                       (instance && isMethodCall && $.isFunction(instance[options]) &&
+                               instance[options].apply(instance, args));
+               });
+       };
+
+       // create widget constructor
+       $[namespace] = $[namespace] || {};
+       $[namespace][name] = function(element, options) {
+               var self = this;
+
+               this.widgetName = name;
+               this.widgetEventPrefix = $[namespace][name].eventPrefix || name;
+               this.widgetBaseClass = namespace + '-' + name;
+
+               this.options = $.extend({},
+                       $.widget.defaults,
+                       $[namespace][name].defaults,
+                       $.metadata && $.metadata.get(element)[name],
+                       options);
+
+               this.element = $(element)
+                       .bind('setData.' + name, function(event, key, value) {
+                               return self._setData(key, value);
+                       })
+                       .bind('getData.' + name, function(event, key) {
+                               return self._getData(key);
+                       })
+                       .bind('remove', function() {
+                               return self.destroy();
+                       });
+
+               this._init();
+       };
+
+       // add widget prototype
+       $[namespace][name].prototype = $.extend({}, $.widget.prototype, prototype);
+
+       // TODO: merge getter and getterSetter properties from widget prototype
+       // and plugin prototype
+       $[namespace][name].getterSetter = 'option';
+};
+
+$.widget.prototype = {
+       _init: function() {},
+       destroy: function() {
+               this.element.removeData(this.widgetName);
+       },
+
+       option: function(key, value) {
+               var options = key,
+                       self = this;
+
+               if (typeof key == "string") {
+                       if (value === undefined) {
+                               return this._getData(key);
+                       }
+                       options = {};
+                       options[key] = value;
+               }
+
+               $.each(options, function(key, value) {
+                       self._setData(key, value);
+               });
+       },
+       _getData: function(key) {
+               return this.options[key];
+       },
+       _setData: function(key, value) {
+               this.options[key] = value;
+
+               if (key == 'disabled') {
+                       this.element[value ? 'addClass' : 'removeClass'](
+                               this.widgetBaseClass + '-disabled');
+               }
+       },
+
+       enable: function() {
+               this._setData('disabled', false);
+       },
+       disable: function() {
+               this._setData('disabled', true);
+       },
+
+       _trigger: function(type, event, data) {
+               var eventName = (type == this.widgetEventPrefix
+                       ? type : this.widgetEventPrefix + type);
+               event = event || $.event.fix({ type: eventName, target: this.element[0] });
+               return this.element.triggerHandler(eventName, [event, data], this.options[type]);
+       }
+};
+
+$.widget.defaults = {
+       disabled: false
+};
+
+
+/** Mouse Interaction Plugin **/
+
+$.ui.mouse = {
+       _mouseInit: function() {
+               var self = this;
+
+               this.element
+                       .bind('mousedown.'+this.widgetName, function(event) {
+                               return self._mouseDown(event);
+                       })
+                       .bind('click.'+this.widgetName, function(event) {
+                               if(self._preventClickEvent) {
+                                       self._preventClickEvent = false;
+                                       return false;
+                               }
+                       });
+
+               // Prevent text selection in IE
+               if ($.browser.msie) {
+                       this._mouseUnselectable = this.element.attr('unselectable');
+                       this.element.attr('unselectable', 'on');
+               }
+
+               this.started = false;
+       },
+
+       // TODO: make sure destroying one instance of mouse doesn't mess with
+       // other instances of mouse
+       _mouseDestroy: function() {
+               this.element.unbind('.'+this.widgetName);
+
+               // Restore text selection in IE
+               ($.browser.msie
+                       && this.element.attr('unselectable', this._mouseUnselectable));
+       },
+
+       _mouseDown: function(event) {
+               // we may have missed mouseup (out of window)
+               (this._mouseStarted && this._mouseUp(event));
+
+               this._mouseDownEvent = event;
+
+               var self = this,
+                       btnIsLeft = (event.which == 1),
+                       elIsCancel = (typeof this.options.cancel == "string" ? $(event.target).parents().add(event.target).filter(this.options.cancel).length : false);
+               if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
+                       return true;
+               }
+
+               this.mouseDelayMet = !this.options.delay;
+               if (!this.mouseDelayMet) {
+                       this._mouseDelayTimer = setTimeout(function() {
+                               self.mouseDelayMet = true;
+                       }, this.options.delay);
+               }
+
+               if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+                       this._mouseStarted = (this._mouseStart(event) !== false);
+                       if (!this._mouseStarted) {
+                               event.preventDefault();
+                               return true;
+                       }
+               }
+
+               // these delegates are required to keep context
+               this._mouseMoveDelegate = function(event) {
+                       return self._mouseMove(event);
+               };
+               this._mouseUpDelegate = function(event) {
+                       return self._mouseUp(event);
+               };
+               $(document)
+                       .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
+                       .bind('mouseup.'+this.widgetName, this._mouseUpDelegate);
+
+               // preventDefault() is used to prevent the selection of text here -
+               // however, in Safari, this causes select boxes not to be selectable
+               // anymore, so this fix is needed
+               if(!$.browser.safari) event.preventDefault();
+               return true;
+       },
+
+       _mouseMove: function(event) {
+               // IE mouseup check - mouseup happened when mouse was out of window
+               if ($.browser.msie && !event.button) {
+                       return this._mouseUp(event);
+               }
+
+               if (this._mouseStarted) {
+                       this._mouseDrag(event);
+                       return event.preventDefault();
+               }
+
+               if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+                       this._mouseStarted =
+                               (this._mouseStart(this._mouseDownEvent, event) !== false);
+                       (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
+               }
+
+               return !this._mouseStarted;
+       },
+
+       _mouseUp: function(event) {
+               $(document)
+                       .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
+                       .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
+
+               if (this._mouseStarted) {
+                       this._mouseStarted = false;
+                       this._preventClickEvent = true;
+                       this._mouseStop(event);
+               }
+
+               return false;
+       },
+
+       _mouseDistanceMet: function(event) {
+               return (Math.max(
+                               Math.abs(this._mouseDownEvent.pageX - event.pageX),
+                               Math.abs(this._mouseDownEvent.pageY - event.pageY)
+                       ) >= this.options.distance
+               );
+       },
+
+       _mouseDelayMet: function(event) {
+               return this.mouseDelayMet;
+       },
+
+       // These are placeholder methods, to be overriden by extending plugin
+       _mouseStart: function(event) {},
+       _mouseDrag: function(event) {},
+       _mouseStop: function(event) {},
+       _mouseCapture: function(event) { return true; }
+};
+
+$.ui.mouse.defaults = {
+       cancel: null,
+       distance: 1,
+       delay: 0
+};
+
+})(jQuery);
+/*
+ * jQuery UI Draggable 1.6
+ *
+ * Copyright (c) 2008 AUTHORS.txt (http://ui.jquery.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Draggables
+ *
+ * Depends:
+ *     ui.core.js
+ */
+(function($) {
+
+$.widget("ui.draggable", $.extend({}, $.ui.mouse, {
+
+       _init: function() {
+
+               if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position")))
+                       this.element[0].style.position = 'relative';
+
+               (this.options.cssNamespace && this.element.addClass(this.options.cssNamespace+"-draggable"));
+               (this.options.disabled && this.element.addClass('ui-draggable-disabled'));
+
+               this._mouseInit();
+
+       },
+
+       destroy: function() {
+               if(!this.element.data('draggable')) return;
+               this.element.removeData("draggable").unbind(".draggable").removeClass('ui-draggable ui-draggable-dragging ui-draggable-disabled');
+               this._mouseDestroy();
+       },
+
+       _mouseCapture: function(event) {
+
+               var o = this.options;
+
+               if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle'))
+                       return false;
+
+               //Quit if we're not on a valid handle
+               this.handle = this._getHandle(event);
+               if (!this.handle)
+                       return false;
+
+               return true;
+
+       },
+
+       _mouseStart: function(event) {
+
+               var o = this.options;
+
+               //Create and append the visible helper
+               this.helper = this._createHelper(event);
+
+               //Cache the helper size
+               this._cacheHelperProportions();
+
+               //If ddmanager is used for droppables, set the global draggable
+               if($.ui.ddmanager)
+                       $.ui.ddmanager.current = this;
+
+               /*
+                * - Position generation -
+                * This block generates everything position related - it's the core of draggables.
+                */
+
+               //Cache the margins of the original element
+               this._cacheMargins();
+
+               //Store the helper's css position
+               this.cssPosition = this.helper.css("position");
+               this.scrollParent = this.helper.scrollParent();
+
+               //The element's absolute position on the page minus margins
+               this.offset = this.element.offset();
+               this.offset = {
+                       top: this.offset.top - this.margins.top,
+                       left: this.offset.left - this.margins.left
+               };
+
+               $.extend(this.offset, {
+                       click: { //Where the click happened, relative to the element
+                               left: event.pageX - this.offset.left,
+                               top: event.pageY - this.offset.top
+                       },
+                       parent: this._getParentOffset(),
+                       relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
+               });
+
+               //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
+               if(o.cursorAt)
+                       this._adjustOffsetFromHelper(o.cursorAt);
+
+               //Generate the original position
+               this.originalPosition = this._generatePosition(event);
+
+               //Set a containment if given in the options
+               if(o.containment)
+                       this._setContainment();
+
+               //Call plugins and callbacks
+               this._propagate("start", event);
+
+               //Recache the helper size
+               this._cacheHelperProportions();
+
+               //Prepare the droppable offsets
+               if ($.ui.ddmanager && !o.dropBehaviour)
+                       $.ui.ddmanager.prepareOffsets(this, event);
+
+               this.helper.addClass("ui-draggable-dragging");
+               this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
+               return true;
+       },
+
+       _mouseDrag: function(event, noPropagation) {
+
+               //Compute the helpers position
+               this.position = this._generatePosition(event);
+               this.positionAbs = this._convertPositionTo("absolute");
+
+               //Call plugins and callbacks and use the resulting position if something is returned
+               if(!noPropagation) this.position = this._propagate("drag", event) || this.position;
+
+               if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
+               if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
+               if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
+
+               return false;
+       },
+
+       _mouseStop: function(event) {
+
+               //If we are using droppables, inform the manager about the drop
+               var dropped = false;
+               if ($.ui.ddmanager && !this.options.dropBehaviour)
+                       var dropped = $.ui.ddmanager.drop(this, event);
+
+               if((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) {
+                       var self = this;
+                       $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
+                               self._propagate("stop", event);
+                               self._clear();
+                       });
+               } else {
+                       this._propagate("stop", event);
+                       this._clear();
+               }
+
+               return false;
+       },
+
+       _getHandle: function(event) {
+
+               var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false;
+               $(this.options.handle, this.element)
+                       .find("*")
+                       .andSelf()
+                       .each(function() {
+                               if(this == event.target) handle = true;
+                       });
+
+               return handle;
+
+       },
+
+       _createHelper: function(event) {
+
+               var o = this.options;
+               var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone() : this.element);
+
+               if(!helper.parents('body').length)
+                       helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo));
+
+               if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position")))
+                       helper.css("position", "absolute");
+
+               return helper;
+
+       },
+
+       _adjustOffsetFromHelper: function(obj) {
+               if(obj.left != undefined) this.offset.click.left = obj.left + this.margins.left;
+               if(obj.right != undefined) this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+               if(obj.top != undefined) this.offset.click.top = obj.top + this.margins.top;
+               if(obj.bottom != undefined) this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
+       },
+
+       _getParentOffset: function() {
+
+               this.offsetParent = this.helper.offsetParent(); var po = this.offsetParent.offset();                    //Get the offsetParent and cache its position
+
+               if((this.offsetParent[0] == document.body && $.browser.mozilla) //Ugly FF3 fix
+               || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix
+                       po = { top: 0, left: 0 };
+
+               return {
+                       top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
+                       left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
+               };
+
+       },
+
+       _getRelativeOffset: function() {
+
+               if(this.cssPosition == "relative") {
+                       var p = this.element.position();
+                       return {
+                               top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
+                               left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
+                       };
+               } else {
+                       return { top: 0, left: 0 };
+               }
+
+       },
+
+       _cacheMargins: function() {
+               this.margins = {
+                       left: (parseInt(this.element.css("marginLeft"),10) || 0),
+                       top: (parseInt(this.element.css("marginTop"),10) || 0)
+               };
+       },
+
+       _cacheHelperProportions: function() {
+               this.helperProportions = {
+                       width: this.helper.outerWidth(),
+                       height: this.helper.outerHeight()
+               };
+       },
+
+       _setContainment: function() {
+
+               var o = this.options;
+               if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
+               if(o.containment == 'document' || o.containment == 'window') this.containment = [
+                       0 - this.offset.relative.left - this.offset.parent.left,
+                       0 - this.offset.relative.top - this.offset.parent.top,
+                       $(o.containment == 'document' ? document : window).width() - this.offset.relative.left - this.offset.parent.left - this.helperProportions.width - this.margins.left - (parseInt(this.element.css("marginRight"),10) || 0),
+                       ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.offset.relative.top - this.offset.parent.top - this.helperProportions.height - this.margins.top - (parseInt(this.element.css("marginBottom"),10) || 0)
+               ];
+
+               if(!(/^(document|window|parent)$/).test(o.containment)) {
+                       var ce = $(o.containment)[0];
+                       var co = $(o.containment).offset();
+                       var over = ($(ce).css("overflow") != 'hidden');
+
+                       this.containment = [
+                               co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) - this.offset.relative.left - this.offset.parent.left - this.margins.left,
+                               co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) - this.offset.relative.top - this.offset.parent.top - this.margins.top,
+                               co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - this.offset.relative.left - this.offset.parent.left - this.helperProportions.width - this.margins.left,
+                               co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - this.offset.relative.top - this.offset.parent.top - this.helperProportions.height - this.margins.top
+                       ];
+               }
+
+       },
+
+       _convertPositionTo: function(d, pos) {
+
+               if(!pos) pos = this.position;
+               var mod = d == "absolute" ? 1 : -1;
+               var scroll = this[(this.cssPosition == 'absolute' ? 'offset' : 'scroll')+'Parent'], scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+
+               return {
+                       top: (
+                               pos.top                                                                                                                                 // the calculated relative position
+                               + this.offset.relative.top      * mod                                                                           // Only for relative positioned nodes: Relative offset from element to offset parent
+                               + this.offset.parent.top * mod                                                                                  // The offsetParent's offset without borders (offset + border)
+                               + ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod
+                               + this.margins.top * mod                                                                                                //Add the margin (you don't want the margin counting in intersection methods)
+                       ),
+                       left: (
+                               pos.left                                                                                                                                // the calculated relative position
+                               + this.offset.relative.left     * mod                                                                           // Only for relative positioned nodes: Relative offset from element to offset parent
+                               + this.offset.parent.left * mod                                                                                 // The offsetParent's offset without borders (offset + border)
+                               + ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : ( scrollIsRootNode ? 0 : scroll.scrollLeft() ) ) * mod
+                               + this.margins.left * mod                                                                                               //Add the margin (you don't want the margin counting in intersection methods)
+                       )
+               };
+       },
+
+       _generatePosition: function(event) {
+
+               var o = this.options, scroll = this[(this.cssPosition == 'absolute' ? 'offset' : 'scroll')+'Parent'], scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+
+               var position = {
+                       top: (
+                               event.pageY                                                                                                                             // The absolute mouse position
+                               - this.offset.click.top                                                                                                 // Click offset (relative to the element)
+                               - this.offset.relative.top                                                                                              // Only for relative positioned nodes: Relative offset from element to offset parent
+                               - this.offset.parent.top                                                                                                // The offsetParent's offset without borders (offset + border)
+                               + ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )
+                       ),
+                       left: (
+                               event.pageX                                                                                                                             // The absolute mouse position
+                               - this.offset.click.left                                                                                                // Click offset (relative to the element)
+                               - this.offset.relative.left                                                                                             // Only for relative positioned nodes: Relative offset from element to offset parent
+                               - this.offset.parent.left                                                                                               // The offsetParent's offset without borders (offset + border)
+                               + ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )
+                       )
+               };
+
+               if(!this.originalPosition) return position;                                                                             //If we are not dragging yet, we won't check for options
+
+               /*
+                * - Position constraining -
+                * Constrain the position to a mix of grid, containment.
+                */
+               if(this.containment) {
+                       if(position.left < this.containment[0]) position.left = this.containment[0];
+                       if(position.top < this.containment[1]) position.top = this.containment[1];
+                       if(position.left > this.containment[2]) position.left = this.containment[2];
+                       if(position.top > this.containment[3]) position.top = this.containment[3];
+               }
+
+               if(o.grid) {
+                       var top = this.originalPosition.top + Math.round((position.top - this.originalPosition.top) / o.grid[1]) * o.grid[1];
+                       position.top = this.containment ? (!(top < this.containment[1] || top > this.containment[3]) ? top : (!(top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
+
+                       var left = this.originalPosition.left + Math.round((position.left - this.originalPosition.left) / o.grid[0]) * o.grid[0];
+                       position.left = this.containment ? (!(left < this.containment[0] || left > this.containment[2]) ? left : (!(left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
+               }
+
+               return position;
+       },
+
+       _clear: function() {
+               this.helper.removeClass("ui-draggable-dragging");
+               if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove();
+               //if($.ui.ddmanager) $.ui.ddmanager.current = null;
+               this.helper = null;
+               this.cancelHelperRemoval = false;
+       },
+
+       // From now on bulk stuff - mainly helpers
+
+       _propagate: function(n, event) {
+               $.ui.plugin.call(this, n, [event, this._uiHash()]);
+               if(n == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins
+               return this.element.triggerHandler(n == "drag" ? n : "drag"+n, [event, this._uiHash()], this.options[n]);
+       },
+
+       plugins: {},
+
+       _uiHash: function(event) {
+               return {
+                       helper: this.helper,
+                       position: this.position,
+                       absolutePosition: this.positionAbs,
+                       options: this.options
+               };
+       }
+
+}));
+
+$.extend($.ui.draggable, {
+       version: "1.6",
+       defaults: {
+               appendTo: "parent",
+               axis: false,
+               cancel: ":input",
+               connectToSortable: false,
+               containment: false,
+               cssNamespace: "ui",
+               cursor: "default",
+               cursorAt: null,
+               delay: 0,
+               distance: 1,
+               grid: false,
+               handle: false,
+               helper: "original",
+               iframeFix: false,
+               opacity: 1,
+               refreshPositions: false,
+               revert: false,
+               revertDuration: 500,
+               scope: "default",
+               scroll: true,
+               scrollSensitivity: 20,
+               scrollSpeed: 20,
+               snap: false,
+               snapMode: "both",
+               snapTolerance: 20,
+               stack: false,
+               zIndex: null
+       }
+});
+
+$.ui.plugin.add("draggable", "connectToSortable", {
+       start: function(event, ui) {
+
+               var inst = $(this).data("draggable");
+               inst.sortables = [];
+               $(ui.options.connectToSortable).each(function() {
+                       // 'this' points to a string, and should therefore resolved as query, but instead, if the string is assigned to a variable, it loops through the strings properties,
+                       // so we have to append '' to make it anonymous again
+                       $(this+'').each(function() {
+                               if($.data(this, 'sortable')) {
+                                       var sortable = $.data(this, 'sortable');
+                                       inst.sortables.push({
+                                               instance: sortable,
+                                               shouldRevert: sortable.options.revert
+                                       });
+                                       sortable._refreshItems();       //Do a one-time refresh at start to refresh the containerCache
+                                       sortable._propagate("activate", event, inst);
+                               }
+                       });
+               });
+
+       },
+       stop: function(event, ui) {
+
+               //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
+               var inst = $(this).data("draggable");
+
+               $.each(inst.sortables, function() {
+                       if(this.instance.isOver) {
+                               this.instance.isOver = 0;
+                               inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
+                               this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
+                               if(this.shouldRevert) this.instance.options.revert = true; //revert here
+                               this.instance._mouseStop(event);
+
+                               //Also propagate receive event, since the sortable is actually receiving a element
+                               this.instance.element.triggerHandler("sortreceive", [event, $.extend(this.instance._ui(), { sender: inst.element })], this.instance.options["receive"]);
+
+                               this.instance.options.helper = this.instance.options._helper;
+                               
+                               if(inst.options.helper == 'original') {
+                                       this.instance.currentItem.css({ top: 'auto', left: 'auto' });
+                               }
+
+                       } else {
+                               this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
+                               this.instance._propagate("deactivate", event, inst);
+                       }
+
+               });
+
+       },
+       drag: function(event, ui) {
+
+               var inst = $(this).data("draggable"), self = this;
+
+               var checkPos = function(o) {
+                       var dyClick = this.offset.click.top, dxClick = this.offset.click.left;
+                       var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left;
+                       var itemHeight = o.height, itemWidth = o.width;
+                       var itemTop = o.top, itemLeft = o.left;
+
+                       return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth);
+               };
+
+               $.each(inst.sortables, function(i) {
+
+                       if(checkPos.call(inst, this.instance.containerCache)) {
+
+                               //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
+                               if(!this.instance.isOver) {
+                                       this.instance.isOver = 1;
+                                       //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)
+                                       this.instance.currentItem = $(self).clone().appendTo(this.instance.element).data("sortable-item", true);
+                                       this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
+                                       this.instance.options.helper = function() { return ui.helper[0]; };
+
+                                       event.target = this.instance.currentItem[0];
+                                       this.instance._mouseCapture(event, true);
+                                       this.instance._mouseStart(event, true, true);
+
+                                       //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
+                                       this.instance.offset.click.top = inst.offset.click.top;
+                                       this.instance.offset.click.left = inst.offset.click.left;
+                                       this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
+                                       this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
+
+                                       inst._propagate("toSortable", event);
+
+                               }
+
+                               //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(this.instance.currentItem) this.instance._mouseDrag(event);
+
+                       } 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(this.instance.isOver) {
+                                       this.instance.isOver = 0;
+                                       this.instance.cancelHelperRemoval = true;
+                                       this.instance.options.revert = false; //No revert here
+                                       this.instance._mouseStop(event, true);
+                                       this.instance.options.helper = this.instance.options._helper;
+
+                                       //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
+                                       this.instance.currentItem.remove();
+                                       if(this.instance.placeholder) this.instance.placeholder.remove();
+
+                                       inst._propagate("fromSortable", event);
+                               }
+
+                       };
+
+               });
+
+       }
+});
+
+$.ui.plugin.add("draggable", "cursor", {
+       start: function(event, ui) {
+               var t = $('body');
+               if (t.css("cursor")) ui.options._cursor = t.css("cursor");
+               t.css("cursor", ui.options.cursor);
+       },
+       stop: function(event, ui) {
+               if (ui.options._cursor) $('body').css("cursor", ui.options._cursor);
+       }
+});
+
+$.ui.plugin.add("draggable", "iframeFix", {
+       start: function(event, ui) {
+               $(ui.options.iframeFix === true ? "iframe" : ui.options.iframeFix).each(function() {
+                       $('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>')
+                       .css({
+                               width: this.offsetWidth+"px", height: this.offsetHeight+"px",
+                               position: "absolute", opacity: "0.001", zIndex: 1000
+                       })
+                       .css($(this).offset())
+                       .appendTo("body");
+               });
+       },
+       stop: function(event, ui) {
+               $("div.ui-draggable-iframeFix").each(function() { this.parentNode.removeChild(this); }); //Remove frame helpers
+       }
+});
+
+$.ui.plugin.add("draggable", "opacity", {
+       start: function(event, ui) {
+               var t = $(ui.helper);
+               if(t.css("opacity")) ui.options._opacity = t.css("opacity");
+               t.css('opacity', ui.options.opacity);
+       },
+       stop: function(event, ui) {
+               if(ui.options._opacity) $(ui.helper).css('opacity', ui.options._opacity);
+       }
+});
+
+$.ui.plugin.add("draggable", "scroll", {
+       start: function(event, ui) {
+               var o = ui.options;
+               var i = $(this).data("draggable");
+
+               if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset();
+
+       },
+       drag: function(event, ui) {
+
+               var o = ui.options, scrolled = false;
+               var i = $(this).data("draggable");
+
+               if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') {
+
+                       if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
+                               i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
+                       else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity)
+                               i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
+
+                       if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
+                               i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
+                       else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity)
+                               i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
+
+               } else {
+
+                       if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
+                               scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
+                       else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
+                               scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
+
+                       if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
+                               scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
+                       else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
+                               scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
+
+               }
+
+               if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
+                       $.ui.ddmanager.prepareOffsets(i, event);
+
+
+
+               // This is a special case where we need to modify a offset calculated on start, since the following happened:
+               // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
+               // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
+               //    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
+               if(scrolled !== false && i.cssPosition == 'absolute' && i.scrollParent[0] != document && $.ui.contains(i.scrollParent[0], i.offsetParent[0])) {
+                       i.offset.parent = i._getParentOffset();
+                       
+               }
+               
+               // This is another very weird special case that only happens for relative elements:
+               // 1. If the css position is relative
+               // 2. and the scroll parent is the document or similar to the offset parent
+               // we have to refresh the relative offset during the scroll so there are no jumps
+               if(scrolled !== false && i.cssPosition == 'relative' && !(i.scrollParent[0] != document && i.scrollParent[0] != i.offsetParent[0])) {
+                       i.offset.relative = i._getRelativeOffset();
+               }
+               
+
+       }
+});
+
+$.ui.plugin.add("draggable", "snap", {
+       start: function(event, ui) {
+
+               var inst = $(this).data("draggable");
+               inst.snapElements = [];
+
+               $(ui.options.snap.constructor != String ? ( ui.options.snap.items || ':data(draggable)' ) : ui.options.snap).each(function() {
+                       var $t = $(this); var $o = $t.offset();
+                       if(this != inst.element[0]) inst.snapElements.push({
+                               item: this,
+                               width: $t.outerWidth(), height: $t.outerHeight(),
+                               top: $o.top, left: $o.left
+                       });
+               });
+
+       },
+       drag: function(event, ui) {
+
+               var inst = $(this).data("draggable");
+               var d = ui.options.snapTolerance;
+
+               var x1 = ui.absolutePosition.left, x2 = x1 + inst.helperProportions.width,
+                       y1 = ui.absolutePosition.top, y2 = y1 + inst.helperProportions.height;
+
+               for (var i = inst.snapElements.length - 1; i >= 0; i--){
+
+                       var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width,
+                               t = inst.snapElements[i].top, b = t + inst.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))) {
+                               if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
+                               inst.snapElements[i].snapping = false;
+                               continue;
+                       }
+
+                       if(ui.options.snapMode != 'inner') {
+                               var ts = Math.abs(t - y2) <= d;
+                               var bs = Math.abs(b - y1) <= d;
+                               var ls = Math.abs(l - x2) <= d;
+                               var rs = Math.abs(r - x1) <= d;
+                               if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top;
+                               if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top;
+                               if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left;
+                               if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left;
+                       }
+
+                       var first = (ts || bs || ls || rs);
+
+                       if(ui.options.snapMode != 'outer') {
+                               var ts = Math.abs(t - y1) <= d;
+                               var bs = Math.abs(b - y2) <= d;
+                               var ls = Math.abs(l - x1) <= d;
+                               var rs = Math.abs(r - x2) <= d;
+                               if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top;
+                               if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top;
+                               if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left;
+                               if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left;
+                       }
+
+                       if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first))
+                               (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
+                       inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
+
+               };
+
+       }
+});
+
+$.ui.plugin.add("draggable", "stack", {
+       start: function(event, ui) {
+               var group = $.makeArray($(ui.options.stack.group)).sort(function(a,b) {
+                       return (parseInt($(a).css("zIndex"),10) || ui.options.stack.min) - (parseInt($(b).css("zIndex"),10) || ui.options.stack.min);
+               });
+
+               $(group).each(function(i) {
+                       this.style.zIndex = ui.options.stack.min + i;
+               });
+
+               this[0].style.zIndex = ui.options.stack.min + group.length;
+       }
+});
+
+$.ui.plugin.add("draggable", "zIndex", {
+       start: function(event, ui) {
+               var t = $(ui.helper);
+               if(t.css("zIndex")) ui.options._zIndex = t.css("zIndex");
+               t.css('zIndex', ui.options.zIndex);
+       },
+       stop: function(event, ui) {
+               if(ui.options._zIndex) $(ui.helper).css('zIndex', ui.options._zIndex);
+       }
+});
+
+})(jQuery);
+/*
+ * jQuery UI Sortable 1.6
+ *
+ * Copyright (c) 2008 AUTHORS.txt (http://ui.jquery.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Sortables
+ *
+ * Depends:
+ *     ui.core.js
+ */
+(function($) {
+
+$.widget("ui.sortable", $.extend({}, $.ui.mouse, {
+       _init: function() {
+
+               var o = this.options;
+               this.containerCache = {};
+               this.element.addClass("ui-sortable");
+
+               //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
+               this.offset = this.element.offset();
+
+               //Initialize mouse events for interaction
+               this._mouseInit();
+
+       },
+
+       destroy: function() {
+               this.element
+                       .removeClass("ui-sortable ui-sortable-disabled")
+                       .removeData("sortable")
+                       .unbind(".sortable");
+               this._mouseDestroy();
+
+               for ( var i = this.items.length - 1; i >= 0; i-- )
+                       this.items[i].item.removeData("sortable-item");
+       },
+
+       _mouseCapture: function(event, overrideHandle) {
+
+               if (this.reverting) {
+                       return false;
+               }
+
+               if(this.options.disabled || this.options.type == 'static') return false;
+
+               //We have to refresh the items data once first
+               this._refreshItems(event);
+
+               //Find out if the clicked node (or one of its parents) is a actual item in this.items
+               var currentItem = null, self = this, nodes = $(event.target).parents().each(function() {
+                       if($.data(this, 'sortable-item') == self) {
+                               currentItem = $(this);
+                               return false;
+                       }
+               });
+               if($.data(event.target, 'sortable-item') == self) currentItem = $(event.target);
+
+               if(!currentItem) return false;
+               if(this.options.handle && !overrideHandle) {
+                       var validHandle = false;
+
+                       $(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; });
+                       if(!validHandle) return false;
+               }
+
+               this.currentItem = currentItem;
+               this._removeCurrentsFromItems();
+               return true;
+
+       },
+
+       _mouseStart: function(event, overrideHandle, noActivation) {
+
+               var o = this.options;
+               this.currentContainer = this;
+
+               //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
+               this.refreshPositions();
+
+               //Create and append the visible helper
+               this.helper = this._createHelper(event);
+
+               //Cache the helper size
+               this._cacheHelperProportions();
+
+               /*
+                * - Position generation -
+                * This block generates everything position related - it's the core of draggables.
+                */
+
+               //Cache the margins of the original element
+               this._cacheMargins();
+
+               //Get the next scrolling parent
+               this.scrollParent = this.helper.scrollParent();
+
+               //The element's absolute position on the page minus margins
+               this.offset = this.currentItem.offset();
+
+               this.offset = {
+                       top: this.offset.top - this.margins.top,
+                       left: this.offset.left - this.margins.left
+               };
+
+               // Only after we got the offset, we can change the helper's position to absolute
+               // TODO: Still need to figure out a way to make relative sorting possible
+               this.helper.css("position", "absolute");
+               this.cssPosition = this.helper.css("position");
+
+               $.extend(this.offset, {
+                       click: { //Where the click happened, relative to the element
+                               left: event.pageX - this.offset.left,
+                               top: event.pageY - this.offset.top
+                       },
+                       parent: this._getParentOffset(),
+                       relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
+               });
+
+               //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
+               if(o.cursorAt)
+                       this._adjustOffsetFromHelper(o.cursorAt);
+
+               //Generate the original position
+               this.originalPosition = this._generatePosition(event);
+
+               //Cache the former DOM position
+               this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
+
+               //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way
+               if(this.helper[0] != this.currentItem[0]) {
+                       this.currentItem.hide();
+               }
+
+               //Create the placeholder
+               this._createPlaceholder();
+
+               //Set a containment if given in the options
+               if(o.containment)
+                       this._setContainment();
+
+               //Call plugins and callbacks
+               this._propagate("start", event);
+
+               //Recache the helper size
+               if(!this._preserveHelperProportions)
+                       this._cacheHelperProportions();
+
+
+               //Post 'activate' events to possible containers
+               if(!noActivation) {
+                        for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._propagate("activate", event, this); }
+               }
+
+               //Prepare possible droppables
+               if($.ui.ddmanager)
+                       $.ui.ddmanager.current = this;
+
+               if ($.ui.ddmanager && !o.dropBehaviour)
+                       $.ui.ddmanager.prepareOffsets(this, event);
+
+               this.dragging = true;
+
+               this.helper.addClass('ui-sortable-helper');
+               this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
+               return true;
+
+       },
+
+       _mouseDrag: function(event) {
+
+               //Compute the helpers position
+               this.position = this._generatePosition(event);
+               this.positionAbs = this._convertPositionTo("absolute");
+
+               if (!this.lastPositionAbs) {
+                       this.lastPositionAbs = this.positionAbs;
+               }
+
+               //Call the internal plugins
+               $.ui.plugin.call(this, "sort", [event, this._ui()]);
+
+               //Regenerate the absolute position used for position checks
+               this.positionAbs = this._convertPositionTo("absolute");
+
+               //Set the helper position
+               if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
+               if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
+
+               //Rearrange
+               for (var i = this.items.length - 1; i >= 0; i--) {
+
+                       //Cache variables and intersection, continue if no intersection
+                       var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
+                       if (!intersection) continue;
+
+                       if(itemElement != this.currentItem[0] //cannot intersect with itself
+                               &&      this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
+                               &&      !$.ui.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
+                               && (this.options.type == 'semi-dynamic' ? !$.ui.contains(this.element[0], itemElement) : true)
+                       ) {
+
+                               this.direction = intersection == 1 ? "down" : "up";
+
+                               if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
+                                       this.options.sortIndicator.call(this, event, item);
+                               } else {
+                                       break;
+                               }
+
+                               this._propagate("change", event); //Call plugins and callbacks
+                               break;
+                       }
+               }
+
+               //Post events to containers
+               this._contactContainers(event);
+
+               //Interconnect with droppables
+               if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
+
+               //Call callbacks
+               this._trigger('sort', event, this._ui());
+
+               this.lastPositionAbs = this.positionAbs;
+               return false;
+
+       },
+
+       _mouseStop: function(event, noPropagation) {
+
+               if(!event) return;
+
+               //If we are using droppables, inform the manager about the drop
+               if ($.ui.ddmanager && !this.options.dropBehaviour)
+                       $.ui.ddmanager.drop(this, event);
+
+               if(this.options.revert) {
+                       var self = this;
+                       var cur = self.placeholder.offset();
+
+                       self.reverting = true;
+
+                       $(this.helper).animate({
+                               left: cur.left - this.offset.parent.left - self.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft),
+                               top: cur.top - this.offset.parent.top - self.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop)
+                       }, parseInt(this.options.revert, 10) || 500, function() {
+                               self._clear(event);
+                       });
+               } else {
+                       this._clear(event, noPropagation);
+               }
+
+               return false;
+
+       },
+
+       cancel: function() {
+
+               if(this.dragging) {
+
+                       this._mouseUp();
+
+                       if(this.options.helper == "original")
+                               this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
+                       else
+                               this.currentItem.show();
+
+                       //Post deactivating events to containers
+                       for (var i = this.containers.length - 1; i >= 0; i--){
+                               this.containers[i]._propagate("deactivate", null, this);
+                               if(this.containers[i].containerCache.over) {
+                                       this.containers[i]._propagate("out", null, this);
+                                       this.containers[i].containerCache.over = 0;
+                               }
+                       }
+
+               }
+
+               //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
+               if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
+               if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove();
+
+               $.extend(this, {
+                       helper: null,
+                       dragging: false,
+                       reverting: false,
+                       _noFinalSort: null
+               });
+
+               if(this.domPosition.prev) {
+                       $(this.domPosition.prev).after(this.currentItem);
+               } else {
+                       $(this.domPosition.parent).prepend(this.currentItem);
+               }
+
+               return true;
+
+       },
+
+       serialize: function(o) {
+
+               var items = this._getItemsAsjQuery(o && o.connected);
+               var str = []; o = o || {};
+
+               $(items).each(function() {
+                       var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
+                       if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2]));
+               });
+
+               return str.join('&');
+
+       },
+
+       toArray: function(o) {
+
+               var items = this._getItemsAsjQuery(o && o.connected);
+               var ret = []; o = o || {};
+
+               items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); });
+               return ret;
+
+       },
+
+       /* Be careful with the following core functions */
+       _intersectsWith: function(item) {
+
+               var x1 = this.positionAbs.left,
+                       x2 = x1 + this.helperProportions.width,
+                       y1 = this.positionAbs.top,
+                       y2 = y1 + this.helperProportions.height;
+
+               var l = item.left,
+                       r = l + item.width,
+                       t = item.top,
+                       b = t + item.height;
+
+               var dyClick = this.offset.click.top,
+                       dxClick = this.offset.click.left;
+
+               var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r;
+
+               if(        this.options.tolerance == "pointer"
+                       || this.options.forcePointerForContainers
+                       || (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height'])
+               ) {
+                       return isOverElement;
+               } else {
+
+                       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
+
+               }
+       },
+
+       _intersectsWithPointer: function(item) {
+
+               var isOverElementHeight = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
+                       isOverElementWidth = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
+                       isOverElement = isOverElementHeight && isOverElementWidth,
+                       verticalDirection = this._getDragVerticalDirection(),
+                       horizontalDirection = this._getDragHorizontalDirection();
+
+               if (!isOverElement)
+                       return false;
+
+               return this.floating ?
+                       ( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 )
+                       : ( verticalDirection && (verticalDirection == "down" ? 2 : 1) );
+
+       },
+
+       _intersectsWithSides: function(item) {
+
+               var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
+                       isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
+                       verticalDirection = this._getDragVerticalDirection(),
+                       horizontalDirection = this._getDragHorizontalDirection();
+
+               if (this.floating && horizontalDirection) {
+                       return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf));
+               } else {
+                       return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf));
+               }
+
+       },
+
+       _getDragVerticalDirection: function() {
+               var delta = this.positionAbs.top - this.lastPositionAbs.top;
+               return delta != 0 && (delta > 0 ? "down" : "up");
+       },
+
+       _getDragHorizontalDirection: function() {
+               var delta = this.positionAbs.left - this.lastPositionAbs.left;
+               return delta != 0 && (delta > 0 ? "right" : "left");
+       },
+
+       refresh: function(event) {
+               this._refreshItems(event);
+               this.refreshPositions();
+       },
+
+       _getItemsAsjQuery: function(connected) {
+
+               var self = this;
+               var items = [];
+               var queries = [];
+
+               if(this.options.connectWith && connected) {
+                       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 != this && !inst.options.disabled) {
+                                               queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper"), inst]);
+                                       }
+                               };
+                       };
+               }
+
+               queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper"), this]);
+
+               for (var i = queries.length - 1; i >= 0; i--){
+                       queries[i][0].each(function() {
+                               items.push(this);
+                       });
+               };
+
+               return $(items);
+
+       },
+
+       _removeCurrentsFromItems: function() {
+
+               var list = this.currentItem.find(":data(sortable-item)");
+
+               for (var i=0; i < this.items.length; i++) {
+
+                       for (var j=0; j < list.length; j++) {
+                               if(list[j] == this.items[i].item[0])
+                                       this.items.splice(i,1);
+                       };
+
+               };
+
+       },
+
+       _refreshItems: function(event) {
+
+               this.items = [];
+               this.containers = [this];
+               var items = this.items;
+               var self = this;
+               var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]];
+
+               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 != this && !inst.options.disabled) {
+                                               queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
+                                               this.containers.push(inst);
+                                       }
+                               };
+                       };
+               }
+
+               for (var i = queries.length - 1; i >= 0; i--) {
+                       var targetData = queries[i][1];
+                       var _queries = queries[i][0];
+
+                       for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) {
+                               var item = $(_queries[j]);
+
+                               item.data('sortable-item', targetData); // Data for target checking (mouse manager)
+
+                               items.push({
+                                       item: item,
+                                       instance: targetData,
+                                       width: 0, height: 0,
+                                       left: 0, top: 0
+                               });
+                       };
+               };
+
+       },
+
+       refreshPositions: function(fast) {
+
+               //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
+               if(this.offsetParent && this.helper) {
+                       this.offset.parent = this._getParentOffset();
+               }
+
+               for (var i = this.items.length - 1; i >= 0; i--){
+                       var item = this.items[i];
+
+                       //We ignore calculating positions of all connected containers when we're not over them
+                       if(item.instance != this.currentContainer && this.currentContainer && item.item[0] != this.currentItem[0])
+                               continue;
+
+                       var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
+
+                       if (!fast) {
+                               if (this.options.accurateIntersection) {
+                                       item.width = t.outerWidth();
+                                       item.height = t.outerHeight();
+                               }
+                               else {
+                                       item.width = t[0].offsetWidth;
+                                       item.height = t[0].offsetHeight;
+                               }
+                       }
+
+                       var p = t.offset();
+                       item.left = p.left;
+                       item.top = p.top;
+               };
+
+               if(this.options.custom && this.options.custom.refreshContainers) {
+                       this.options.custom.refreshContainers.call(this);
+               } else {
+                       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();
+                       };
+               }
+
+       },
+
+       _createPlaceholder: function(that) {
+
+               var self = that || this, o = self.options;
+
+               if(!o.placeholder || o.placeholder.constructor == String) {
+                       var className = o.placeholder;
+                       o.placeholder = {
+                               element: function() {
+
+                                       var el = $(document.createElement(self.currentItem[0].nodeName))
+                                               .addClass(className || self.currentItem[0].className+" ui-sortable-placeholder")
+                                               .removeClass('ui-sortable-helper')[0];
+
+                                       if(!className) {
+                                               el.style.visibility = "hidden";
+                                               document.body.appendChild(el);
+                                               // Name attributes are removed, otherwice causes elements to be unchecked
+                                               // Expando attributes also have to be removed because of stupid IE (no condition, doesn't hurt in other browsers)
+                                               el.innerHTML = self.currentItem[0].innerHTML.replace(/name\=\"[^\"\']+\"/g, '').replace(/jQuery[0-9]+\=\"[^\"\']+\"/g, '');
+                                               document.body.removeChild(el);
+                                       };
+
+                                       return el;
+                               },
+                               update: function(container, p) {
+                                       if(className && !o.forcePlaceholderSize) return;
+                                       if(!p.height()) { p.height(self.currentItem.innerHeight() - parseInt(self.currentItem.css('paddingTop')||0, 10) - parseInt(self.currentItem.css('paddingBottom')||0, 10)); };
+                                       if(!p.width()) { p.width(self.currentItem.innerWidth() - parseInt(self.currentItem.css('paddingLeft')||0, 10) - parseInt(self.currentItem.css('paddingRight')||0, 10)); };
+                               }
+                       };
+               }
+
+               //Create the placeholder
+               self.placeholder = $(o.placeholder.element.call(self.element, self.currentItem));
+
+               //Append it after the actual current item
+               self.currentItem.after(self.placeholder);
+
+               //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
+               o.placeholder.update(self, self.placeholder);
+
+       },
+
+       _contactContainers: function(event) {
+               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.positionAbs[this.containers[i].floating ? 'left' : 'top'];
+                                               for (var j = this.items.length - 1; j >= 0; j--) {
+                                                       if(!$.ui.contains(this.containers[i].element[0], 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];
+                                                       }
+                                               }
+
+                                               if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled
+                                                       continue;
+
+                                               this.currentContainer = this.containers[i];
+                                               itemWithLeastDistance ? this.options.sortIndicator.call(this, event, itemWithLeastDistance, null, true) : this.options.sortIndicator.call(this, event, null, this.containers[i].element, true);
+                                               this._propagate("change", event); //Call plugins and callbacks
+                                               this.containers[i]._propagate("change", event, this); //Call plugins and callbacks
+
+                                               //Update the placeholder
+                                               this.options.placeholder.update(this.currentContainer, this.placeholder);
+
+                                       }
+
+                                       this.containers[i]._propagate("over", event, this);
+                                       this.containers[i].containerCache.over = 1;
+                               }
+                       } else {
+                               if(this.containers[i].containerCache.over) {
+                                       this.containers[i]._propagate("out", event, this);
+                                       this.containers[i].containerCache.over = 0;
+                               }
+                       }
+
+               };
+       },
+
+       _createHelper: function(event) {
+
+               var o = this.options;
+               var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem);
+
+               if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already
+                       $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
+
+               if(helper[0] == this.currentItem[0])
+                       this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") };
+
+               if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width());
+               if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height());
+
+               return helper;
+
+       },
+
+       _adjustOffsetFromHelper: function(obj) {
+               if(obj.left != undefined) this.offset.click.left = obj.left + this.margins.left;
+               if(obj.right != undefined) this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+               if(obj.top != undefined) this.offset.click.top = obj.top + this.margins.top;
+               if(obj.bottom != undefined) this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
+       },
+
+       _getParentOffset: function() {
+
+               //Get the offsetParent and cache its position
+               this.offsetParent = this.helper.offsetParent(); var po = this.offsetParent.offset();
+
+               if((this.offsetParent[0] == document.body && $.browser.mozilla) //Ugly FF3 fix
+               || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix
+                       po = { top: 0, left: 0 };
+
+               return {
+                       top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
+                       left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
+               };
+
+       },
+
+       _getRelativeOffset: function() {
+
+               if(this.cssPosition == "relative") {
+                       var p = this.currentItem.position();
+                       return {
+                               top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
+                               left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
+                       };
+               } else {
+                       return { top: 0, left: 0 };
+               }
+
+       },
+
+       _cacheMargins: function() {
+               this.margins = {
+                       left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
+                       top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
+               };
+       },
+
+       _cacheHelperProportions: function() {
+               this.helperProportions = {
+                       width: this.helper.outerWidth(),
+                       height: this.helper.outerHeight()
+               };
+       },
+
+       _setContainment: function() {
+
+               var o = this.options;
+               if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
+               if(o.containment == 'document' || o.containment == 'window') this.containment = [
+                       0 - this.offset.relative.left - this.offset.parent.left,
+                       0 - this.offset.relative.top - this.offset.parent.top,
+                       $(o.containment == 'document' ? document : window).width() - this.offset.relative.left - this.offset.parent.left - this.margins.left - (parseInt(this.currentItem.css("marginRight"),10) || 0),
+                       ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.offset.relative.top - this.offset.parent.top - this.margins.top - (parseInt(this.currentItem.css("marginBottom"),10) || 0)
+               ];
+
+               if(!(/^(document|window|parent)$/).test(o.containment)) {
+                       var ce = $(o.containment)[0];
+                       var co = $(o.containment).offset();
+                       var over = ($(ce).css("overflow") != 'hidden');
+
+                       this.containment = [
+                               co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) - this.offset.relative.left - this.offset.parent.left - this.margins.left,
+                               co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) - this.offset.relative.top - this.offset.parent.top - this.margins.top,
+                               co.left + (over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - this.offset.relative.left - this.offset.parent.left - this.margins.left,
+                               co.top + (over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - this.offset.relative.top - this.offset.parent.top - this.margins.top
+                       ];
+               }
+
+       },
+
+       _convertPositionTo: function(d, pos) {
+
+               if(!pos) pos = this.position;
+               var mod = d == "absolute" ? 1 : -1;
+               var scroll = this[(this.cssPosition == 'absolute' ? 'offset' : 'scroll')+'Parent'], scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+
+               return {
+                       top: (
+                               pos.top                                                                                                                                 // the calculated relative position
+                               + this.offset.relative.top      * mod                                                                           // Only for relative positioned nodes: Relative offset from element to offset parent
+                               + this.offset.parent.top * mod                                                                                  // The offsetParent's offset without borders (offset + border)
+                               + ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod
+                               + this.margins.top * mod                                                                                                //Add the margin (you don't want the margin counting in intersection methods)
+                       ),
+                       left: (
+                               pos.left                                                                                                                                // the calculated relative position
+                               + this.offset.relative.left     * mod                                                                           // Only for relative positioned nodes: Relative offset from element to offset parent
+                               + this.offset.parent.left * mod                                                                                 // The offsetParent's offset without borders (offset + border)
+                               + ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : ( scrollIsRootNode ? 0 : scroll.scrollLeft() ) ) * mod
+                               + this.margins.left * mod                                                                                               //Add the margin (you don't want the margin counting in intersection methods)
+                       )
+               };
+       },
+
+       _generatePosition: function(event) {
+
+               var o = this.options, scroll = this[(this.cssPosition == 'absolute' ? 'offset' : 'scroll')+'Parent'], scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+
+               var position = {
+                       top: (
+                               event.pageY                                                                                                                             // The absolute mouse position
+                               - this.offset.click.top                                                                                                 // Click offset (relative to the element)
+                               - this.offset.relative.top                                                                                              // Only for relative positioned nodes: Relative offset from element to offset parent
+                               - this.offset.parent.top                                                                                                // The offsetParent's offset without borders (offset + border)
+                               + ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )
+                       ),
+                       left: (
+                               event.pageX                                                                                                                             // The absolute mouse position
+                               - this.offset.click.left                                                                                                // Click offset (relative to the element)
+                               - this.offset.relative.left                                                                                             // Only for relative positioned nodes: Relative offset from element to offset parent
+                               - this.offset.parent.left                                                                                               // The offsetParent's offset without borders (offset + border)
+                               + ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : ( scrollIsRootNode ? 0 : scroll.scrollLeft() ) )
+                       )
+               };
+
+               if(!this.originalPosition) return position;                                                                             //If we are not dragging yet, we won't check for options
+
+               /*
+                * - Position constraining -
+                * Constrain the position to a mix of grid, containment.
+                */
+               if(this.containment) {
+                       if(position.left < this.containment[0]) position.left = this.containment[0];
+                       if(position.top < this.containment[1]) position.top = this.containment[1];
+                       if(position.left + this.helperProportions.width > this.containment[2]) position.left = this.containment[2] - this.helperProportions.width;
+                       if(position.top + this.helperProportions.height > this.containment[3]) position.top = this.containment[3] - this.helperProportions.height;
+               }
+
+               if(o.grid) {
+                       var top = this.originalPosition.top + Math.round((position.top - this.originalPosition.top) / o.grid[1]) * o.grid[1];
+                       position.top = this.containment ? (!(top < this.containment[1] || top > this.containment[3]) ? top : (!(top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
+
+                       var left = this.originalPosition.left + Math.round((position.left - this.originalPosition.left) / o.grid[0]) * o.grid[0];
+                       position.left = this.containment ? (!(left < this.containment[0] || left > this.containment[2]) ? left : (!(left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
+               }
+
+               return position;
+       },
+
+       _rearrange: function(event, i, a, hardRefresh) {
+
+               a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling));
+
+               //Various things done here to improve the performance:
+               // 1. we create a setTimeout, that calls refreshPositions
+               // 2. on the instance, we have a counter variable, that get's higher after every append
+               // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
+               // 4. this lets only the last addition to the timeout stack through
+               this.counter = this.counter ? ++this.counter : 1;
+               var self = this, counter = this.counter;
+
+               window.setTimeout(function() {
+                       if(counter == self.counter) self.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
+               },0);
+
+       },
+
+       _clear: function(event, noPropagation) {
+
+               this.reverting = false;
+
+               //We first have to update the dom position of the actual currentItem
+               if(!this._noFinalSort) this.placeholder.before(this.currentItem);
+               this._noFinalSort = null;
+
+               if(this.helper[0] == this.currentItem[0]) {
+                       for(var i in this._storedCSS) {
+                               if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = '';
+                       }
+                       this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
+               } else {
+                       this.currentItem.show();
+               }
+
+               if(this.domPosition.prev != this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent != this.currentItem.parent()[0]) this._propagate("update", event, null, noPropagation); //Trigger update callback if the DOM position has changed
+               if(!$.ui.contains(this.element[0], this.currentItem[0])) { //Node was moved out of the current element
+                       this._propagate("remove", event, null, noPropagation);
+                       for (var i = this.containers.length - 1; i >= 0; i--){
+                               if($.ui.contains(this.containers[i].element[0], this.currentItem[0])) {
+                                       this.containers[i]._propagate("update", event, this, noPropagation);
+                                       this.containers[i]._propagate("receive", event, this, noPropagation);
+                               }
+                       };
+               };
+
+               //Post events to containers
+               for (var i = this.containers.length - 1; i >= 0; i--){
+                       this.containers[i]._propagate("deactivate", event, this, noPropagation);
+                       if(this.containers[i].containerCache.over) {
+                               this.containers[i]._propagate("out", event, this);
+                               this.containers[i].containerCache.over = 0;
+                       }
+               }
+
+               this.dragging = false;
+               if(this.cancelHelperRemoval) {
+                       this._propagate("beforeStop", event, null, noPropagation);
+                       this._propagate("stop", event, null, noPropagation);
+                       return false;
+               }
+
+               this._propagate("beforeStop", event, null, noPropagation);
+
+               //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
+               this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
+
+               if(this.options.helper != "original") this.helper.remove(); this.helper = null;
+               this._propagate("stop", event, null, noPropagation);
+
+               return true;
+
+       },
+
+       _propagate: function(n, event, inst, noPropagation) {
+               $.ui.plugin.call(this, n, [event, this._ui(inst)]);
+               var dontCancel = !noPropagation ? this.element.triggerHandler(n == "sort" ? n : "sort"+n, [event, this._ui(inst)], this.options[n]) : true;
+               if(dontCancel === false) this.cancel();
+       },
+
+       plugins: {},
+
+       _ui: function(inst) {
+               var self = inst || this;
+               return {
+                       helper: self.helper,
+                       placeholder: self.placeholder || $([]),
+                       position: self.position,
+                       absolutePosition: self.positionAbs,
+                       item: self.currentItem,
+                       sender: inst ? inst.element : null
+               };
+       }
+
+}));
+
+$.extend($.ui.sortable, {
+       getter: "serialize toArray",
+       version: "1.6",
+       defaults: {
+               accurateIntersection: true,
+               appendTo: "parent",
+               cancel: ":input",
+               delay: 0,
+               distance: 1,
+               dropOnEmpty: true,
+               forcePlaceholderSize: false,
+               forceHelperSize: false,
+               helper: "original",
+               items: '> *',
+               scope: "default",
+               scroll: true,
+               scrollSensitivity: 20,
+               scrollSpeed: 20,
+               sortIndicator: $.ui.sortable.prototype._rearrange,
+               tolerance: "default",
+               zIndex: 1000
+       }
+});
+
+/*
+ * Sortable Extensions
+ */
+
+$.ui.plugin.add("sortable", "cursor", {
+       start: function(event, ui) {
+               var t = $('body'), i = $(this).data('sortable');
+               if (t.css("cursor")) i.options._cursor = t.css("cursor");
+               t.css("cursor", i.options.cursor);
+       },
+       beforeStop: function(event, ui) {
+               var i = $(this).data('sortable');
+               if (i.options._cursor) $('body').css("cursor", i.options._cursor);
+       }
+});
+
+$.ui.plugin.add("sortable", "opacity", {
+       start: function(event, ui) {
+               var t = ui.helper, i = $(this).data('sortable');
+               if(t.css("opacity")) i.options._opacity = t.css("opacity");
+               t.css('opacity', i.options.opacity);
+       },
+       beforeStop: function(event, ui) {
+               var i = $(this).data('sortable');
+               if(i.options._opacity) $(ui.helper).css('opacity', i.options._opacity);
+       }
+});
+
+$.ui.plugin.add("sortable", "scroll", {
+       start: function(event, ui) {
+               var i = $(this).data("sortable"), o = i.options;
+               if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset();
+       },
+       sort: function(event, ui) {
+
+               var i = $(this).data("sortable"), o = i.options, scrolled = false;
+
+               if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') {
+
+                       if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
+                               i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
+                       else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity)
+                               i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
+
+                       if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
+                               i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
+                       else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity)
+                               i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
+
+               } else {
+
+                       if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
+                               scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
+                       else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
+                               scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
+
+                       if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
+                               scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
+                       else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
+                               scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
+
+               }
+
+               if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
+                       $.ui.ddmanager.prepareOffsets(i, event);
+
+
+
+               //This is a special case where we need to modify a offset calculated on start, since the following happened:
+               // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
+               // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
+               //    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
+               if(scrolled !== false && i.cssPosition == 'absolute' && i.scrollParent[0] != document && $.ui.contains(i.scrollParent[0], i.offsetParent[0])) {
+                       i.offset.parent = i._getParentOffset();
+               }
+               
+               // This is another very weird special case that only happens for relative elements:
+               // 1. If the css position is relative
+               // 2. and the scroll parent is the document or similar to the offset parent
+               // we have to refresh the relative offset during the scroll so there are no jumps
+               if(scrolled !== false && i.cssPosition == 'relative' && !(i.scrollParent[0] != document && i.scrollParent[0] != i.offsetParent[0])) {
+                       i.offset.relative = i._getRelativeOffset();
+               }
+
+       }
+});
+
+$.ui.plugin.add("sortable", "zIndex", {
+       start: function(event, ui) {
+               var t = ui.helper, i = $(this).data('sortable');
+               if(t.css("zIndex")) i.options._zIndex = t.css("zIndex");
+               t.css('zIndex', i.options.zIndex);
+       },
+       beforeStop: function(event, ui) {
+               var i = $(this).data('sortable');
+               if(i.options._zIndex) $(ui.helper).css('zIndex', i.options._zIndex == 'auto' ? '' : i.options._zIndex);
+       }
+});
+
+})(jQuery);