[SPIP] +2.1.12
[velocampus/web/www.git] / www / plugins / auto / spip-bonux / formulaires / selecteur / jquery-ui-1.6.custom.js
1 /*
2 * jQuery UI 1.6
3 *
4 * Copyright (c) 2008 AUTHORS.txt (http://ui.jquery.com/about)
5 * Dual licensed under the MIT (MIT-LICENSE.txt)
6 * and GPL (GPL-LICENSE.txt) licenses.
7 *
8 * http://docs.jquery.com/UI
9 */
10 ;(function($) {
11
12 var _remove = $.fn.remove,
13 isFF2 = $.browser.mozilla && (parseFloat($.browser.version) < 1.9);
14
15 //Helper functions and ui object
16 $.ui = {
17
18 version: "1.6",
19
20 // $.ui.plugin is deprecated. Use the proxy pattern instead.
21 plugin: {
22 add: function(module, option, set) {
23 var proto = $.ui[module].prototype;
24 for(var i in set) {
25 proto.plugins[i] = proto.plugins[i] || [];
26 proto.plugins[i].push([option, set[i]]);
27 }
28 },
29 call: function(instance, name, args) {
30 var set = instance.plugins[name];
31 if(!set) { return; }
32
33 for (var i = 0; i < set.length; i++) {
34 if (instance.options[set[i][0]]) {
35 set[i][1].apply(instance.element, args);
36 }
37 }
38 }
39 },
40
41 contains: function(a, b) {
42 var safari2 = $.browser.safari && $.browser.version < 522;
43 if (a.contains && !safari2) {
44 return a.contains(b);
45 }
46 if (a.compareDocumentPosition)
47 return !!(a.compareDocumentPosition(b) & 16);
48 while (b = b.parentNode)
49 if (b == a) return true;
50 return false;
51 },
52
53 cssCache: {},
54 css: function(name) {
55 if ($.ui.cssCache[name]) { return $.ui.cssCache[name]; }
56 var tmp = $('<div class="ui-gen">').addClass(name).css({position:'absolute', top:'-5000px', left:'-5000px', display:'block'}).appendTo('body');
57
58 //if (!$.browser.safari)
59 //tmp.appendTo('body');
60
61 //Opera and Safari set width and height to 0px instead of auto
62 //Safari returns rgba(0,0,0,0) when bgcolor is not set
63 $.ui.cssCache[name] = !!(
64 (!(/auto|default/).test(tmp.css('cursor')) || (/^[1-9]/).test(tmp.css('height')) || (/^[1-9]/).test(tmp.css('width')) ||
65 !(/none/).test(tmp.css('backgroundImage')) || !(/transparent|rgba\(0, 0, 0, 0\)/).test(tmp.css('backgroundColor')))
66 );
67 try { $('body').get(0).removeChild(tmp.get(0)); } catch(e){}
68 return $.ui.cssCache[name];
69 },
70
71 hasScroll: function(el, a) {
72
73 //If overflow is hidden, the element might have extra content, but the user wants to hide it
74 if ($(el).css('overflow') == 'hidden') { return false; }
75
76 var scroll = (a && a == 'left') ? 'scrollLeft' : 'scrollTop',
77 has = false;
78
79 if (el[scroll] > 0) { return true; }
80
81 // TODO: determine which cases actually cause this to happen
82 // if the element doesn't have the scroll set, see if it's possible to
83 // set the scroll
84 el[scroll] = 1;
85 has = (el[scroll] > 0);
86 el[scroll] = 0;
87 return has;
88 },
89
90 isOverAxis: function(x, reference, size) {
91 //Determines when x coordinate is over "b" element axis
92 return (x > reference) && (x < (reference + size));
93 },
94
95 isOver: function(y, x, top, left, height, width) {
96 //Determines when x, y coordinates is over "b" element
97 return $.ui.isOverAxis(y, top, height) && $.ui.isOverAxis(x, left, width);
98 },
99
100 keyCode: {
101 BACKSPACE: 8,
102 CAPS_LOCK: 20,
103 COMMA: 188,
104 CONTROL: 17,
105 DELETE: 46,
106 DOWN: 40,
107 END: 35,
108 ENTER: 13,
109 ESCAPE: 27,
110 HOME: 36,
111 INSERT: 45,
112 LEFT: 37,
113 NUMPAD_ADD: 107,
114 NUMPAD_DECIMAL: 110,
115 NUMPAD_DIVIDE: 111,
116 NUMPAD_ENTER: 108,
117 NUMPAD_MULTIPLY: 106,
118 NUMPAD_SUBTRACT: 109,
119 PAGE_DOWN: 34,
120 PAGE_UP: 33,
121 PERIOD: 190,
122 RIGHT: 39,
123 SHIFT: 16,
124 SPACE: 32,
125 TAB: 9,
126 UP: 38
127 }
128
129 };
130
131 // WAI-ARIA normalization
132 if (isFF2) {
133 var attr = $.attr,
134 removeAttr = $.fn.removeAttr,
135 ariaNS = "http://www.w3.org/2005/07/aaa",
136 ariaState = /^aria-/,
137 ariaRole = /^wairole:/;
138
139 $.attr = function(elem, name, value) {
140 var set = value !== undefined;
141
142 return (name == 'role'
143 ? (set
144 ? attr.call(this, elem, name, "wairole:" + value)
145 : (attr.apply(this, arguments) || "").replace(ariaRole, ""))
146 : (ariaState.test(name)
147 ? (set
148 ? elem.setAttributeNS(ariaNS,
149 name.replace(ariaState, "aaa:"), value)
150 : attr.call(this, elem, name.replace(ariaState, "aaa:")))
151 : attr.apply(this, arguments)));
152 };
153
154 $.fn.removeAttr = function(name) {
155 return (ariaState.test(name)
156 ? this.each(function() {
157 this.removeAttributeNS(ariaNS, name.replace(ariaState, ""));
158 }) : removeAttr.call(this, name));
159 };
160 }
161
162 //jQuery plugins
163 $.fn.extend({
164
165 remove: function() {
166 // Safari has a native remove event which actually removes DOM elements,
167 // so we have to use triggerHandler instead of trigger (#3037).
168 $("*", this).add(this).each(function() {
169 $(this).triggerHandler("remove");
170 });
171 return _remove.apply(this, arguments );
172 },
173
174 enableSelection: function() {
175 return this
176 .attr('unselectable', 'off')
177 .css('MozUserSelect', '')
178 .unbind('selectstart.ui');
179 },
180
181 disableSelection: function() {
182 return this
183 .attr('unselectable', 'on')
184 .css('MozUserSelect', 'none')
185 .bind('selectstart.ui', function() { return false; });
186 },
187
188 scrollParent: function() {
189
190 var scrollParent;
191 if(($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) {
192 scrollParent = this.parents().filter(function() {
193 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));
194 }).eq(0);
195 } else {
196 scrollParent = this.parents().filter(function() {
197 return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
198 }).eq(0);
199 }
200
201 return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent;
202
203
204 }
205
206 });
207
208
209 //Additional selectors
210 $.extend($.expr[':'], {
211
212 data: function(a, i, m) {
213 return $.data(a, m[3]);
214 },
215
216 // TODO: add support for object, area
217 tabbable: function(a, i, m) {
218
219 var nodeName = a.nodeName.toLowerCase();
220 function isVisible(element) {
221 return !($(element).is(':hidden') || $(element).parents(':hidden').length);
222 }
223
224 return (
225 // in tab order
226 a.tabIndex >= 0 &&
227
228 ( // filter node types that participate in the tab order
229
230 // anchor tag
231 ('a' == nodeName && a.href) ||
232
233 // enabled form element
234 (/input|select|textarea|button/.test(nodeName) &&
235 'hidden' != a.type && !a.disabled)
236 ) &&
237
238 // visible on page
239 isVisible(a)
240 );
241
242 }
243
244 });
245
246
247 // $.widget is a factory to create jQuery plugins
248 // taking some boilerplate code out of the plugin code
249 function getter(namespace, plugin, method, args) {
250 function getMethods(type) {
251 var methods = $[namespace][plugin][type] || [];
252 return (typeof methods == 'string' ? methods.split(/,?\s+/) : methods);
253 }
254
255 var methods = getMethods('getter');
256 if (args.length == 1 && typeof args[0] == 'string') {
257 methods = methods.concat(getMethods('getterSetter'));
258 }
259 return ($.inArray(method, methods) != -1);
260 }
261
262 $.widget = function(name, prototype) {
263 var namespace = name.split(".")[0];
264 name = name.split(".")[1];
265
266 // create plugin method
267 $.fn[name] = function(options) {
268 var isMethodCall = (typeof options == 'string'),
269 args = Array.prototype.slice.call(arguments, 1);
270
271 // prevent calls to internal methods
272 if (isMethodCall && options.substring(0, 1) == '_') {
273 return this;
274 }
275
276 // handle getter methods
277 if (isMethodCall && getter(namespace, name, options, args)) {
278 var instance = $.data(this[0], name);
279 return (instance ? instance[options].apply(instance, args)
280 : undefined);
281 }
282
283 // handle initialization and non-getter methods
284 return this.each(function() {
285 var instance = $.data(this, name);
286
287 // constructor
288 (!instance && !isMethodCall &&
289 $.data(this, name, new $[namespace][name](this, options)));
290
291 // method call
292 (instance && isMethodCall && $.isFunction(instance[options]) &&
293 instance[options].apply(instance, args));
294 });
295 };
296
297 // create widget constructor
298 $[namespace] = $[namespace] || {};
299 $[namespace][name] = function(element, options) {
300 var self = this;
301
302 this.widgetName = name;
303 this.widgetEventPrefix = $[namespace][name].eventPrefix || name;
304 this.widgetBaseClass = namespace + '-' + name;
305
306 this.options = $.extend({},
307 $.widget.defaults,
308 $[namespace][name].defaults,
309 $.metadata && $.metadata.get(element)[name],
310 options);
311
312 this.element = $(element)
313 .bind('setData.' + name, function(event, key, value) {
314 return self._setData(key, value);
315 })
316 .bind('getData.' + name, function(event, key) {
317 return self._getData(key);
318 })
319 .bind('remove', function() {
320 return self.destroy();
321 });
322
323 this._init();
324 };
325
326 // add widget prototype
327 $[namespace][name].prototype = $.extend({}, $.widget.prototype, prototype);
328
329 // TODO: merge getter and getterSetter properties from widget prototype
330 // and plugin prototype
331 $[namespace][name].getterSetter = 'option';
332 };
333
334 $.widget.prototype = {
335 _init: function() {},
336 destroy: function() {
337 this.element.removeData(this.widgetName);
338 },
339
340 option: function(key, value) {
341 var options = key,
342 self = this;
343
344 if (typeof key == "string") {
345 if (value === undefined) {
346 return this._getData(key);
347 }
348 options = {};
349 options[key] = value;
350 }
351
352 $.each(options, function(key, value) {
353 self._setData(key, value);
354 });
355 },
356 _getData: function(key) {
357 return this.options[key];
358 },
359 _setData: function(key, value) {
360 this.options[key] = value;
361
362 if (key == 'disabled') {
363 this.element[value ? 'addClass' : 'removeClass'](
364 this.widgetBaseClass + '-disabled');
365 }
366 },
367
368 enable: function() {
369 this._setData('disabled', false);
370 },
371 disable: function() {
372 this._setData('disabled', true);
373 },
374
375 _trigger: function(type, event, data) {
376 var eventName = (type == this.widgetEventPrefix
377 ? type : this.widgetEventPrefix + type);
378 event = event || $.event.fix({ type: eventName, target: this.element[0] });
379 return this.element.triggerHandler(eventName, [event, data], this.options[type]);
380 }
381 };
382
383 $.widget.defaults = {
384 disabled: false
385 };
386
387
388 /** Mouse Interaction Plugin **/
389
390 $.ui.mouse = {
391 _mouseInit: function() {
392 var self = this;
393
394 this.element
395 .bind('mousedown.'+this.widgetName, function(event) {
396 return self._mouseDown(event);
397 })
398 .bind('click.'+this.widgetName, function(event) {
399 if(self._preventClickEvent) {
400 self._preventClickEvent = false;
401 return false;
402 }
403 });
404
405 // Prevent text selection in IE
406 if ($.browser.msie) {
407 this._mouseUnselectable = this.element.attr('unselectable');
408 this.element.attr('unselectable', 'on');
409 }
410
411 this.started = false;
412 },
413
414 // TODO: make sure destroying one instance of mouse doesn't mess with
415 // other instances of mouse
416 _mouseDestroy: function() {
417 this.element.unbind('.'+this.widgetName);
418
419 // Restore text selection in IE
420 ($.browser.msie
421 && this.element.attr('unselectable', this._mouseUnselectable));
422 },
423
424 _mouseDown: function(event) {
425 // we may have missed mouseup (out of window)
426 (this._mouseStarted && this._mouseUp(event));
427
428 this._mouseDownEvent = event;
429
430 var self = this,
431 btnIsLeft = (event.which == 1),
432 elIsCancel = (typeof this.options.cancel == "string" ? $(event.target).parents().add(event.target).filter(this.options.cancel).length : false);
433 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
434 return true;
435 }
436
437 this.mouseDelayMet = !this.options.delay;
438 if (!this.mouseDelayMet) {
439 this._mouseDelayTimer = setTimeout(function() {
440 self.mouseDelayMet = true;
441 }, this.options.delay);
442 }
443
444 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
445 this._mouseStarted = (this._mouseStart(event) !== false);
446 if (!this._mouseStarted) {
447 event.preventDefault();
448 return true;
449 }
450 }
451
452 // these delegates are required to keep context
453 this._mouseMoveDelegate = function(event) {
454 return self._mouseMove(event);
455 };
456 this._mouseUpDelegate = function(event) {
457 return self._mouseUp(event);
458 };
459 $(document)
460 .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
461 .bind('mouseup.'+this.widgetName, this._mouseUpDelegate);
462
463 // preventDefault() is used to prevent the selection of text here -
464 // however, in Safari, this causes select boxes not to be selectable
465 // anymore, so this fix is needed
466 if(!$.browser.safari) event.preventDefault();
467 return true;
468 },
469
470 _mouseMove: function(event) {
471 // IE mouseup check - mouseup happened when mouse was out of window
472 if ($.browser.msie && !event.button) {
473 return this._mouseUp(event);
474 }
475
476 if (this._mouseStarted) {
477 this._mouseDrag(event);
478 return event.preventDefault();
479 }
480
481 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
482 this._mouseStarted =
483 (this._mouseStart(this._mouseDownEvent, event) !== false);
484 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
485 }
486
487 return !this._mouseStarted;
488 },
489
490 _mouseUp: function(event) {
491 $(document)
492 .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
493 .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
494
495 if (this._mouseStarted) {
496 this._mouseStarted = false;
497 this._preventClickEvent = true;
498 this._mouseStop(event);
499 }
500
501 return false;
502 },
503
504 _mouseDistanceMet: function(event) {
505 return (Math.max(
506 Math.abs(this._mouseDownEvent.pageX - event.pageX),
507 Math.abs(this._mouseDownEvent.pageY - event.pageY)
508 ) >= this.options.distance
509 );
510 },
511
512 _mouseDelayMet: function(event) {
513 return this.mouseDelayMet;
514 },
515
516 // These are placeholder methods, to be overriden by extending plugin
517 _mouseStart: function(event) {},
518 _mouseDrag: function(event) {},
519 _mouseStop: function(event) {},
520 _mouseCapture: function(event) { return true; }
521 };
522
523 $.ui.mouse.defaults = {
524 cancel: null,
525 distance: 1,
526 delay: 0
527 };
528
529 })(jQuery);
530 /*
531 * jQuery UI Draggable 1.6
532 *
533 * Copyright (c) 2008 AUTHORS.txt (http://ui.jquery.com/about)
534 * Dual licensed under the MIT (MIT-LICENSE.txt)
535 * and GPL (GPL-LICENSE.txt) licenses.
536 *
537 * http://docs.jquery.com/UI/Draggables
538 *
539 * Depends:
540 * ui.core.js
541 */
542 (function($) {
543
544 $.widget("ui.draggable", $.extend({}, $.ui.mouse, {
545
546 _init: function() {
547
548 if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position")))
549 this.element[0].style.position = 'relative';
550
551 (this.options.cssNamespace && this.element.addClass(this.options.cssNamespace+"-draggable"));
552 (this.options.disabled && this.element.addClass('ui-draggable-disabled'));
553
554 this._mouseInit();
555
556 },
557
558 destroy: function() {
559 if(!this.element.data('draggable')) return;
560 this.element.removeData("draggable").unbind(".draggable").removeClass('ui-draggable ui-draggable-dragging ui-draggable-disabled');
561 this._mouseDestroy();
562 },
563
564 _mouseCapture: function(event) {
565
566 var o = this.options;
567
568 if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle'))
569 return false;
570
571 //Quit if we're not on a valid handle
572 this.handle = this._getHandle(event);
573 if (!this.handle)
574 return false;
575
576 return true;
577
578 },
579
580 _mouseStart: function(event) {
581
582 var o = this.options;
583
584 //Create and append the visible helper
585 this.helper = this._createHelper(event);
586
587 //Cache the helper size
588 this._cacheHelperProportions();
589
590 //If ddmanager is used for droppables, set the global draggable
591 if($.ui.ddmanager)
592 $.ui.ddmanager.current = this;
593
594 /*
595 * - Position generation -
596 * This block generates everything position related - it's the core of draggables.
597 */
598
599 //Cache the margins of the original element
600 this._cacheMargins();
601
602 //Store the helper's css position
603 this.cssPosition = this.helper.css("position");
604 this.scrollParent = this.helper.scrollParent();
605
606 //The element's absolute position on the page minus margins
607 this.offset = this.element.offset();
608 this.offset = {
609 top: this.offset.top - this.margins.top,
610 left: this.offset.left - this.margins.left
611 };
612
613 $.extend(this.offset, {
614 click: { //Where the click happened, relative to the element
615 left: event.pageX - this.offset.left,
616 top: event.pageY - this.offset.top
617 },
618 parent: this._getParentOffset(),
619 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
620 });
621
622 //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
623 if(o.cursorAt)
624 this._adjustOffsetFromHelper(o.cursorAt);
625
626 //Generate the original position
627 this.originalPosition = this._generatePosition(event);
628
629 //Set a containment if given in the options
630 if(o.containment)
631 this._setContainment();
632
633 //Call plugins and callbacks
634 this._propagate("start", event);
635
636 //Recache the helper size
637 this._cacheHelperProportions();
638
639 //Prepare the droppable offsets
640 if ($.ui.ddmanager && !o.dropBehaviour)
641 $.ui.ddmanager.prepareOffsets(this, event);
642
643 this.helper.addClass("ui-draggable-dragging");
644 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
645 return true;
646 },
647
648 _mouseDrag: function(event, noPropagation) {
649
650 //Compute the helpers position
651 this.position = this._generatePosition(event);
652 this.positionAbs = this._convertPositionTo("absolute");
653
654 //Call plugins and callbacks and use the resulting position if something is returned
655 if(!noPropagation) this.position = this._propagate("drag", event) || this.position;
656
657 if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
658 if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
659 if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
660
661 return false;
662 },
663
664 _mouseStop: function(event) {
665
666 //If we are using droppables, inform the manager about the drop
667 var dropped = false;
668 if ($.ui.ddmanager && !this.options.dropBehaviour)
669 var dropped = $.ui.ddmanager.drop(this, event);
670
671 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))) {
672 var self = this;
673 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
674 self._propagate("stop", event);
675 self._clear();
676 });
677 } else {
678 this._propagate("stop", event);
679 this._clear();
680 }
681
682 return false;
683 },
684
685 _getHandle: function(event) {
686
687 var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false;
688 $(this.options.handle, this.element)
689 .find("*")
690 .andSelf()
691 .each(function() {
692 if(this == event.target) handle = true;
693 });
694
695 return handle;
696
697 },
698
699 _createHelper: function(event) {
700
701 var o = this.options;
702 var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone() : this.element);
703
704 if(!helper.parents('body').length)
705 helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo));
706
707 if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position")))
708 helper.css("position", "absolute");
709
710 return helper;
711
712 },
713
714 _adjustOffsetFromHelper: function(obj) {
715 if(obj.left != undefined) this.offset.click.left = obj.left + this.margins.left;
716 if(obj.right != undefined) this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
717 if(obj.top != undefined) this.offset.click.top = obj.top + this.margins.top;
718 if(obj.bottom != undefined) this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
719 },
720
721 _getParentOffset: function() {
722
723 this.offsetParent = this.helper.offsetParent(); var po = this.offsetParent.offset(); //Get the offsetParent and cache its position
724
725 if((this.offsetParent[0] == document.body && $.browser.mozilla) //Ugly FF3 fix
726 || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix
727 po = { top: 0, left: 0 };
728
729 return {
730 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
731 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
732 };
733
734 },
735
736 _getRelativeOffset: function() {
737
738 if(this.cssPosition == "relative") {
739 var p = this.element.position();
740 return {
741 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
742 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
743 };
744 } else {
745 return { top: 0, left: 0 };
746 }
747
748 },
749
750 _cacheMargins: function() {
751 this.margins = {
752 left: (parseInt(this.element.css("marginLeft"),10) || 0),
753 top: (parseInt(this.element.css("marginTop"),10) || 0)
754 };
755 },
756
757 _cacheHelperProportions: function() {
758 this.helperProportions = {
759 width: this.helper.outerWidth(),
760 height: this.helper.outerHeight()
761 };
762 },
763
764 _setContainment: function() {
765
766 var o = this.options;
767 if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
768 if(o.containment == 'document' || o.containment == 'window') this.containment = [
769 0 - this.offset.relative.left - this.offset.parent.left,
770 0 - this.offset.relative.top - this.offset.parent.top,
771 $(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),
772 ($(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)
773 ];
774
775 if(!(/^(document|window|parent)$/).test(o.containment)) {
776 var ce = $(o.containment)[0];
777 var co = $(o.containment).offset();
778 var over = ($(ce).css("overflow") != 'hidden');
779
780 this.containment = [
781 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) - this.offset.relative.left - this.offset.parent.left - this.margins.left,
782 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) - this.offset.relative.top - this.offset.parent.top - this.margins.top,
783 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,
784 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
785 ];
786 }
787
788 },
789
790 _convertPositionTo: function(d, pos) {
791
792 if(!pos) pos = this.position;
793 var mod = d == "absolute" ? 1 : -1;
794 var scroll = this[(this.cssPosition == 'absolute' ? 'offset' : 'scroll')+'Parent'], scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
795
796 return {
797 top: (
798 pos.top // the calculated relative position
799 + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent
800 + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border)
801 + ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod
802 + this.margins.top * mod //Add the margin (you don't want the margin counting in intersection methods)
803 ),
804 left: (
805 pos.left // the calculated relative position
806 + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent
807 + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border)
808 + ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : ( scrollIsRootNode ? 0 : scroll.scrollLeft() ) ) * mod
809 + this.margins.left * mod //Add the margin (you don't want the margin counting in intersection methods)
810 )
811 };
812 },
813
814 _generatePosition: function(event) {
815
816 var o = this.options, scroll = this[(this.cssPosition == 'absolute' ? 'offset' : 'scroll')+'Parent'], scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
817
818 var position = {
819 top: (
820 event.pageY // The absolute mouse position
821 - this.offset.click.top // Click offset (relative to the element)
822 - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent
823 - this.offset.parent.top // The offsetParent's offset without borders (offset + border)
824 + ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )
825 ),
826 left: (
827 event.pageX // The absolute mouse position
828 - this.offset.click.left // Click offset (relative to the element)
829 - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent
830 - this.offset.parent.left // The offsetParent's offset without borders (offset + border)
831 + ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )
832 )
833 };
834
835 if(!this.originalPosition) return position; //If we are not dragging yet, we won't check for options
836
837 /*
838 * - Position constraining -
839 * Constrain the position to a mix of grid, containment.
840 */
841 if(this.containment) {
842 if(position.left < this.containment[0]) position.left = this.containment[0];
843 if(position.top < this.containment[1]) position.top = this.containment[1];
844 if(position.left > this.containment[2]) position.left = this.containment[2];
845 if(position.top > this.containment[3]) position.top = this.containment[3];
846 }
847
848 if(o.grid) {
849 var top = this.originalPosition.top + Math.round((position.top - this.originalPosition.top) / o.grid[1]) * o.grid[1];
850 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;
851
852 var left = this.originalPosition.left + Math.round((position.left - this.originalPosition.left) / o.grid[0]) * o.grid[0];
853 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;
854 }
855
856 return position;
857 },
858
859 _clear: function() {
860 this.helper.removeClass("ui-draggable-dragging");
861 if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove();
862 //if($.ui.ddmanager) $.ui.ddmanager.current = null;
863 this.helper = null;
864 this.cancelHelperRemoval = false;
865 },
866
867 // From now on bulk stuff - mainly helpers
868
869 _propagate: function(n, event) {
870 $.ui.plugin.call(this, n, [event, this._uiHash()]);
871 if(n == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins
872 return this.element.triggerHandler(n == "drag" ? n : "drag"+n, [event, this._uiHash()], this.options[n]);
873 },
874
875 plugins: {},
876
877 _uiHash: function(event) {
878 return {
879 helper: this.helper,
880 position: this.position,
881 absolutePosition: this.positionAbs,
882 options: this.options
883 };
884 }
885
886 }));
887
888 $.extend($.ui.draggable, {
889 version: "1.6",
890 defaults: {
891 appendTo: "parent",
892 axis: false,
893 cancel: ":input",
894 connectToSortable: false,
895 containment: false,
896 cssNamespace: "ui",
897 cursor: "default",
898 cursorAt: null,
899 delay: 0,
900 distance: 1,
901 grid: false,
902 handle: false,
903 helper: "original",
904 iframeFix: false,
905 opacity: 1,
906 refreshPositions: false,
907 revert: false,
908 revertDuration: 500,
909 scope: "default",
910 scroll: true,
911 scrollSensitivity: 20,
912 scrollSpeed: 20,
913 snap: false,
914 snapMode: "both",
915 snapTolerance: 20,
916 stack: false,
917 zIndex: null
918 }
919 });
920
921 $.ui.plugin.add("draggable", "connectToSortable", {
922 start: function(event, ui) {
923
924 var inst = $(this).data("draggable");
925 inst.sortables = [];
926 $(ui.options.connectToSortable).each(function() {
927 // '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,
928 // so we have to append '' to make it anonymous again
929 $(this+'').each(function() {
930 if($.data(this, 'sortable')) {
931 var sortable = $.data(this, 'sortable');
932 inst.sortables.push({
933 instance: sortable,
934 shouldRevert: sortable.options.revert
935 });
936 sortable._refreshItems(); //Do a one-time refresh at start to refresh the containerCache
937 sortable._propagate("activate", event, inst);
938 }
939 });
940 });
941
942 },
943 stop: function(event, ui) {
944
945 //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
946 var inst = $(this).data("draggable");
947
948 $.each(inst.sortables, function() {
949 if(this.instance.isOver) {
950 this.instance.isOver = 0;
951 inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
952 this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
953 if(this.shouldRevert) this.instance.options.revert = true; //revert here
954 this.instance._mouseStop(event);
955
956 //Also propagate receive event, since the sortable is actually receiving a element
957 this.instance.element.triggerHandler("sortreceive", [event, $.extend(this.instance._ui(), { sender: inst.element })], this.instance.options["receive"]);
958
959 this.instance.options.helper = this.instance.options._helper;
960
961 if(inst.options.helper == 'original') {
962 this.instance.currentItem.css({ top: 'auto', left: 'auto' });
963 }
964
965 } else {
966 this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
967 this.instance._propagate("deactivate", event, inst);
968 }
969
970 });
971
972 },
973 drag: function(event, ui) {
974
975 var inst = $(this).data("draggable"), self = this;
976
977 var checkPos = function(o) {
978 var dyClick = this.offset.click.top, dxClick = this.offset.click.left;
979 var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left;
980 var itemHeight = o.height, itemWidth = o.width;
981 var itemTop = o.top, itemLeft = o.left;
982
983 return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth);
984 };
985
986 $.each(inst.sortables, function(i) {
987
988 if(checkPos.call(inst, this.instance.containerCache)) {
989
990 //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
991 if(!this.instance.isOver) {
992 this.instance.isOver = 1;
993 //Now we fake the start of dragging for the sortable instance,
994 //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
995 //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)
996 this.instance.currentItem = $(self).clone().appendTo(this.instance.element).data("sortable-item", true);
997 this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
998 this.instance.options.helper = function() { return ui.helper[0]; };
999
1000 event.target = this.instance.currentItem[0];
1001 this.instance._mouseCapture(event, true);
1002 this.instance._mouseStart(event, true, true);
1003
1004 //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
1005 this.instance.offset.click.top = inst.offset.click.top;
1006 this.instance.offset.click.left = inst.offset.click.left;
1007 this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
1008 this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
1009
1010 inst._propagate("toSortable", event);
1011
1012 }
1013
1014 //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
1015 if(this.instance.currentItem) this.instance._mouseDrag(event);
1016
1017 } else {
1018
1019 //If it doesn't intersect with the sortable, and it intersected before,
1020 //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
1021 if(this.instance.isOver) {
1022 this.instance.isOver = 0;
1023 this.instance.cancelHelperRemoval = true;
1024 this.instance.options.revert = false; //No revert here
1025 this.instance._mouseStop(event, true);
1026 this.instance.options.helper = this.instance.options._helper;
1027
1028 //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
1029 this.instance.currentItem.remove();
1030 if(this.instance.placeholder) this.instance.placeholder.remove();
1031
1032 inst._propagate("fromSortable", event);
1033 }
1034
1035 };
1036
1037 });
1038
1039 }
1040 });
1041
1042 $.ui.plugin.add("draggable", "cursor", {
1043 start: function(event, ui) {
1044 var t = $('body');
1045 if (t.css("cursor")) ui.options._cursor = t.css("cursor");
1046 t.css("cursor", ui.options.cursor);
1047 },
1048 stop: function(event, ui) {
1049 if (ui.options._cursor) $('body').css("cursor", ui.options._cursor);
1050 }
1051 });
1052
1053 $.ui.plugin.add("draggable", "iframeFix", {
1054 start: function(event, ui) {
1055 $(ui.options.iframeFix === true ? "iframe" : ui.options.iframeFix).each(function() {
1056 $('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>')
1057 .css({
1058 width: this.offsetWidth+"px", height: this.offsetHeight+"px",
1059 position: "absolute", opacity: "0.001", zIndex: 1000
1060 })
1061 .css($(this).offset())
1062 .appendTo("body");
1063 });
1064 },
1065 stop: function(event, ui) {
1066 $("div.ui-draggable-iframeFix").each(function() { this.parentNode.removeChild(this); }); //Remove frame helpers
1067 }
1068 });
1069
1070 $.ui.plugin.add("draggable", "opacity", {
1071 start: function(event, ui) {
1072 var t = $(ui.helper);
1073 if(t.css("opacity")) ui.options._opacity = t.css("opacity");
1074 t.css('opacity', ui.options.opacity);
1075 },
1076 stop: function(event, ui) {
1077 if(ui.options._opacity) $(ui.helper).css('opacity', ui.options._opacity);
1078 }
1079 });
1080
1081 $.ui.plugin.add("draggable", "scroll", {
1082 start: function(event, ui) {
1083 var o = ui.options;
1084 var i = $(this).data("draggable");
1085
1086 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset();
1087
1088 },
1089 drag: function(event, ui) {
1090
1091 var o = ui.options, scrolled = false;
1092 var i = $(this).data("draggable");
1093
1094 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') {
1095
1096 if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
1097 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
1098 else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity)
1099 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
1100
1101 if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
1102 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
1103 else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity)
1104 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
1105
1106 } else {
1107
1108 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
1109 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
1110 else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
1111 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
1112
1113 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
1114 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
1115 else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
1116 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
1117
1118 }
1119
1120 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
1121 $.ui.ddmanager.prepareOffsets(i, event);
1122
1123
1124
1125 // This is a special case where we need to modify a offset calculated on start, since the following happened:
1126 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
1127 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
1128 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
1129 if(scrolled !== false && i.cssPosition == 'absolute' && i.scrollParent[0] != document && $.ui.contains(i.scrollParent[0], i.offsetParent[0])) {
1130 i.offset.parent = i._getParentOffset();
1131
1132 }
1133
1134 // This is another very weird special case that only happens for relative elements:
1135 // 1. If the css position is relative
1136 // 2. and the scroll parent is the document or similar to the offset parent
1137 // we have to refresh the relative offset during the scroll so there are no jumps
1138 if(scrolled !== false && i.cssPosition == 'relative' && !(i.scrollParent[0] != document && i.scrollParent[0] != i.offsetParent[0])) {
1139 i.offset.relative = i._getRelativeOffset();
1140 }
1141
1142
1143 }
1144 });
1145
1146 $.ui.plugin.add("draggable", "snap", {
1147 start: function(event, ui) {
1148
1149 var inst = $(this).data("draggable");
1150 inst.snapElements = [];
1151
1152 $(ui.options.snap.constructor != String ? ( ui.options.snap.items || ':data(draggable)' ) : ui.options.snap).each(function() {
1153 var $t = $(this); var $o = $t.offset();
1154 if(this != inst.element[0]) inst.snapElements.push({
1155 item: this,
1156 width: $t.outerWidth(), height: $t.outerHeight(),
1157 top: $o.top, left: $o.left
1158 });
1159 });
1160
1161 },
1162 drag: function(event, ui) {
1163
1164 var inst = $(this).data("draggable");
1165 var d = ui.options.snapTolerance;
1166
1167 var x1 = ui.absolutePosition.left, x2 = x1 + inst.helperProportions.width,
1168 y1 = ui.absolutePosition.top, y2 = y1 + inst.helperProportions.height;
1169
1170 for (var i = inst.snapElements.length - 1; i >= 0; i--){
1171
1172 var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width,
1173 t = inst.snapElements[i].top, b = t + inst.snapElements[i].height;
1174
1175 //Yes, I know, this is insane ;)
1176 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))) {
1177 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 })));
1178 inst.snapElements[i].snapping = false;
1179 continue;
1180 }
1181
1182 if(ui.options.snapMode != 'inner') {
1183 var ts = Math.abs(t - y2) <= d;
1184 var bs = Math.abs(b - y1) <= d;
1185 var ls = Math.abs(l - x2) <= d;
1186 var rs = Math.abs(r - x1) <= d;
1187 if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top;
1188 if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top;
1189 if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left;
1190 if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left;
1191 }
1192
1193 var first = (ts || bs || ls || rs);
1194
1195 if(ui.options.snapMode != 'outer') {
1196 var ts = Math.abs(t - y1) <= d;
1197 var bs = Math.abs(b - y2) <= d;
1198 var ls = Math.abs(l - x1) <= d;
1199 var rs = Math.abs(r - x2) <= d;
1200 if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top;
1201 if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top;
1202 if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left;
1203 if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left;
1204 }
1205
1206 if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first))
1207 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
1208 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
1209
1210 };
1211
1212 }
1213 });
1214
1215 $.ui.plugin.add("draggable", "stack", {
1216 start: function(event, ui) {
1217 var group = $.makeArray($(ui.options.stack.group)).sort(function(a,b) {
1218 return (parseInt($(a).css("zIndex"),10) || ui.options.stack.min) - (parseInt($(b).css("zIndex"),10) || ui.options.stack.min);
1219 });
1220
1221 $(group).each(function(i) {
1222 this.style.zIndex = ui.options.stack.min + i;
1223 });
1224
1225 this[0].style.zIndex = ui.options.stack.min + group.length;
1226 }
1227 });
1228
1229 $.ui.plugin.add("draggable", "zIndex", {
1230 start: function(event, ui) {
1231 var t = $(ui.helper);
1232 if(t.css("zIndex")) ui.options._zIndex = t.css("zIndex");
1233 t.css('zIndex', ui.options.zIndex);
1234 },
1235 stop: function(event, ui) {
1236 if(ui.options._zIndex) $(ui.helper).css('zIndex', ui.options._zIndex);
1237 }
1238 });
1239
1240 })(jQuery);
1241 /*
1242 * jQuery UI Sortable 1.6
1243 *
1244 * Copyright (c) 2008 AUTHORS.txt (http://ui.jquery.com/about)
1245 * Dual licensed under the MIT (MIT-LICENSE.txt)
1246 * and GPL (GPL-LICENSE.txt) licenses.
1247 *
1248 * http://docs.jquery.com/UI/Sortables
1249 *
1250 * Depends:
1251 * ui.core.js
1252 */
1253 (function($) {
1254
1255 $.widget("ui.sortable", $.extend({}, $.ui.mouse, {
1256 _init: function() {
1257
1258 var o = this.options;
1259 this.containerCache = {};
1260 this.element.addClass("ui-sortable");
1261
1262 //Get the items
1263 this.refresh();
1264
1265 //Let's determine if the items are floating
1266 this.floating = this.items.length ? (/left|right/).test(this.items[0].item.css('float')) : false;
1267
1268 //Let's determine the parent's offset
1269 this.offset = this.element.offset();
1270
1271 //Initialize mouse events for interaction
1272 this._mouseInit();
1273
1274 },
1275
1276 destroy: function() {
1277 this.element
1278 .removeClass("ui-sortable ui-sortable-disabled")
1279 .removeData("sortable")
1280 .unbind(".sortable");
1281 this._mouseDestroy();
1282
1283 for ( var i = this.items.length - 1; i >= 0; i-- )
1284 this.items[i].item.removeData("sortable-item");
1285 },
1286
1287 _mouseCapture: function(event, overrideHandle) {
1288
1289 if (this.reverting) {
1290 return false;
1291 }
1292
1293 if(this.options.disabled || this.options.type == 'static') return false;
1294
1295 //We have to refresh the items data once first
1296 this._refreshItems(event);
1297
1298 //Find out if the clicked node (or one of its parents) is a actual item in this.items
1299 var currentItem = null, self = this, nodes = $(event.target).parents().each(function() {
1300 if($.data(this, 'sortable-item') == self) {
1301 currentItem = $(this);
1302 return false;
1303 }
1304 });
1305 if($.data(event.target, 'sortable-item') == self) currentItem = $(event.target);
1306
1307 if(!currentItem) return false;
1308 if(this.options.handle && !overrideHandle) {
1309 var validHandle = false;
1310
1311 $(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; });
1312 if(!validHandle) return false;
1313 }
1314
1315 this.currentItem = currentItem;
1316 this._removeCurrentsFromItems();
1317 return true;
1318
1319 },
1320
1321 _mouseStart: function(event, overrideHandle, noActivation) {
1322
1323 var o = this.options;
1324 this.currentContainer = this;
1325
1326 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
1327 this.refreshPositions();
1328
1329 //Create and append the visible helper
1330 this.helper = this._createHelper(event);
1331
1332 //Cache the helper size
1333 this._cacheHelperProportions();
1334
1335 /*
1336 * - Position generation -
1337 * This block generates everything position related - it's the core of draggables.
1338 */
1339
1340 //Cache the margins of the original element
1341 this._cacheMargins();
1342
1343 //Get the next scrolling parent
1344 this.scrollParent = this.helper.scrollParent();
1345
1346 //The element's absolute position on the page minus margins
1347 this.offset = this.currentItem.offset();
1348
1349 this.offset = {
1350 top: this.offset.top - this.margins.top,
1351 left: this.offset.left - this.margins.left
1352 };
1353
1354 // Only after we got the offset, we can change the helper's position to absolute
1355 // TODO: Still need to figure out a way to make relative sorting possible
1356 this.helper.css("position", "absolute");
1357 this.cssPosition = this.helper.css("position");
1358
1359 $.extend(this.offset, {
1360 click: { //Where the click happened, relative to the element
1361 left: event.pageX - this.offset.left,
1362 top: event.pageY - this.offset.top
1363 },
1364 parent: this._getParentOffset(),
1365 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
1366 });
1367
1368 //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
1369 if(o.cursorAt)
1370 this._adjustOffsetFromHelper(o.cursorAt);
1371
1372 //Generate the original position
1373 this.originalPosition = this._generatePosition(event);
1374
1375 //Cache the former DOM position
1376 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
1377
1378 //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
1379 if(this.helper[0] != this.currentItem[0]) {
1380 this.currentItem.hide();
1381 }
1382
1383 //Create the placeholder
1384 this._createPlaceholder();
1385
1386 //Set a containment if given in the options
1387 if(o.containment)
1388 this._setContainment();
1389
1390 //Call plugins and callbacks
1391 this._propagate("start", event);
1392
1393 //Recache the helper size
1394 if(!this._preserveHelperProportions)
1395 this._cacheHelperProportions();
1396
1397
1398 //Post 'activate' events to possible containers
1399 if(!noActivation) {
1400 for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._propagate("activate", event, this); }
1401 }
1402
1403 //Prepare possible droppables
1404 if($.ui.ddmanager)
1405 $.ui.ddmanager.current = this;
1406
1407 if ($.ui.ddmanager && !o.dropBehaviour)
1408 $.ui.ddmanager.prepareOffsets(this, event);
1409
1410 this.dragging = true;
1411
1412 this.helper.addClass('ui-sortable-helper');
1413 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
1414 return true;
1415
1416 },
1417
1418 _mouseDrag: function(event) {
1419
1420 //Compute the helpers position
1421 this.position = this._generatePosition(event);
1422 this.positionAbs = this._convertPositionTo("absolute");
1423
1424 if (!this.lastPositionAbs) {
1425 this.lastPositionAbs = this.positionAbs;
1426 }
1427
1428 //Call the internal plugins
1429 $.ui.plugin.call(this, "sort", [event, this._ui()]);
1430
1431 //Regenerate the absolute position used for position checks
1432 this.positionAbs = this._convertPositionTo("absolute");
1433
1434 //Set the helper position
1435 if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
1436 if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
1437
1438 //Rearrange
1439 for (var i = this.items.length - 1; i >= 0; i--) {
1440
1441 //Cache variables and intersection, continue if no intersection
1442 var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
1443 if (!intersection) continue;
1444
1445 if(itemElement != this.currentItem[0] //cannot intersect with itself
1446 && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
1447 && !$.ui.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
1448 && (this.options.type == 'semi-dynamic' ? !$.ui.contains(this.element[0], itemElement) : true)
1449 ) {
1450
1451 this.direction = intersection == 1 ? "down" : "up";
1452
1453 if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
1454 this.options.sortIndicator.call(this, event, item);
1455 } else {
1456 break;
1457 }
1458
1459 this._propagate("change", event); //Call plugins and callbacks
1460 break;
1461 }
1462 }
1463
1464 //Post events to containers
1465 this._contactContainers(event);
1466
1467 //Interconnect with droppables
1468 if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
1469
1470 //Call callbacks
1471 this._trigger('sort', event, this._ui());
1472
1473 this.lastPositionAbs = this.positionAbs;
1474 return false;
1475
1476 },
1477
1478 _mouseStop: function(event, noPropagation) {
1479
1480 if(!event) return;
1481
1482 //If we are using droppables, inform the manager about the drop
1483 if ($.ui.ddmanager && !this.options.dropBehaviour)
1484 $.ui.ddmanager.drop(this, event);
1485
1486 if(this.options.revert) {
1487 var self = this;
1488 var cur = self.placeholder.offset();
1489
1490 self.reverting = true;
1491
1492 $(this.helper).animate({
1493 left: cur.left - this.offset.parent.left - self.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft),
1494 top: cur.top - this.offset.parent.top - self.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop)
1495 }, parseInt(this.options.revert, 10) || 500, function() {
1496 self._clear(event);
1497 });
1498 } else {
1499 this._clear(event, noPropagation);
1500 }
1501
1502 return false;
1503
1504 },
1505
1506 cancel: function() {
1507
1508 if(this.dragging) {
1509
1510 this._mouseUp();
1511
1512 if(this.options.helper == "original")
1513 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
1514 else
1515 this.currentItem.show();
1516
1517 //Post deactivating events to containers
1518 for (var i = this.containers.length - 1; i >= 0; i--){
1519 this.containers[i]._propagate("deactivate", null, this);
1520 if(this.containers[i].containerCache.over) {
1521 this.containers[i]._propagate("out", null, this);
1522 this.containers[i].containerCache.over = 0;
1523 }
1524 }
1525
1526 }
1527
1528 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
1529 if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
1530 if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove();
1531
1532 $.extend(this, {
1533 helper: null,
1534 dragging: false,
1535 reverting: false,
1536 _noFinalSort: null
1537 });
1538
1539 if(this.domPosition.prev) {
1540 $(this.domPosition.prev).after(this.currentItem);
1541 } else {
1542 $(this.domPosition.parent).prepend(this.currentItem);
1543 }
1544
1545 return true;
1546
1547 },
1548
1549 serialize: function(o) {
1550
1551 var items = this._getItemsAsjQuery(o && o.connected);
1552 var str = []; o = o || {};
1553
1554 $(items).each(function() {
1555 var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
1556 if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2]));
1557 });
1558
1559 return str.join('&');
1560
1561 },
1562
1563 toArray: function(o) {
1564
1565 var items = this._getItemsAsjQuery(o && o.connected);
1566 var ret = []; o = o || {};
1567
1568 items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); });
1569 return ret;
1570
1571 },
1572
1573 /* Be careful with the following core functions */
1574 _intersectsWith: function(item) {
1575
1576 var x1 = this.positionAbs.left,
1577 x2 = x1 + this.helperProportions.width,
1578 y1 = this.positionAbs.top,
1579 y2 = y1 + this.helperProportions.height;
1580
1581 var l = item.left,
1582 r = l + item.width,
1583 t = item.top,
1584 b = t + item.height;
1585
1586 var dyClick = this.offset.click.top,
1587 dxClick = this.offset.click.left;
1588
1589 var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r;
1590
1591 if( this.options.tolerance == "pointer"
1592 || this.options.forcePointerForContainers
1593 || (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height'])
1594 ) {
1595 return isOverElement;
1596 } else {
1597
1598 return (l < x1 + (this.helperProportions.width / 2) // Right Half
1599 && x2 - (this.helperProportions.width / 2) < r // Left Half
1600 && t < y1 + (this.helperProportions.height / 2) // Bottom Half
1601 && y2 - (this.helperProportions.height / 2) < b ); // Top Half
1602
1603 }
1604 },
1605
1606 _intersectsWithPointer: function(item) {
1607
1608 var isOverElementHeight = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
1609 isOverElementWidth = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
1610 isOverElement = isOverElementHeight && isOverElementWidth,
1611 verticalDirection = this._getDragVerticalDirection(),
1612 horizontalDirection = this._getDragHorizontalDirection();
1613
1614 if (!isOverElement)
1615 return false;
1616
1617 return this.floating ?
1618 ( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 )
1619 : ( verticalDirection && (verticalDirection == "down" ? 2 : 1) );
1620
1621 },
1622
1623 _intersectsWithSides: function(item) {
1624
1625 var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
1626 isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
1627 verticalDirection = this._getDragVerticalDirection(),
1628 horizontalDirection = this._getDragHorizontalDirection();
1629
1630 if (this.floating && horizontalDirection) {
1631 return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf));
1632 } else {
1633 return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf));
1634 }
1635
1636 },
1637
1638 _getDragVerticalDirection: function() {
1639 var delta = this.positionAbs.top - this.lastPositionAbs.top;
1640 return delta != 0 && (delta > 0 ? "down" : "up");
1641 },
1642
1643 _getDragHorizontalDirection: function() {
1644 var delta = this.positionAbs.left - this.lastPositionAbs.left;
1645 return delta != 0 && (delta > 0 ? "right" : "left");
1646 },
1647
1648 refresh: function(event) {
1649 this._refreshItems(event);
1650 this.refreshPositions();
1651 },
1652
1653 _getItemsAsjQuery: function(connected) {
1654
1655 var self = this;
1656 var items = [];
1657 var queries = [];
1658
1659 if(this.options.connectWith && connected) {
1660 for (var i = this.options.connectWith.length - 1; i >= 0; i--){
1661 var cur = $(this.options.connectWith[i]);
1662 for (var j = cur.length - 1; j >= 0; j--){
1663 var inst = $.data(cur[j], 'sortable');
1664 if(inst && inst != this && !inst.options.disabled) {
1665 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper"), inst]);
1666 }
1667 };
1668 };
1669 }
1670
1671 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]);
1672
1673 for (var i = queries.length - 1; i >= 0; i--){
1674 queries[i][0].each(function() {
1675 items.push(this);
1676 });
1677 };
1678
1679 return $(items);
1680
1681 },
1682
1683 _removeCurrentsFromItems: function() {
1684
1685 var list = this.currentItem.find(":data(sortable-item)");
1686
1687 for (var i=0; i < this.items.length; i++) {
1688
1689 for (var j=0; j < list.length; j++) {
1690 if(list[j] == this.items[i].item[0])
1691 this.items.splice(i,1);
1692 };
1693
1694 };
1695
1696 },
1697
1698 _refreshItems: function(event) {
1699
1700 this.items = [];
1701 this.containers = [this];
1702 var items = this.items;
1703 var self = this;
1704 var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]];
1705
1706 if(this.options.connectWith) {
1707 for (var i = this.options.connectWith.length - 1; i >= 0; i--){
1708 var cur = $(this.options.connectWith[i]);
1709 for (var j = cur.length - 1; j >= 0; j--){
1710 var inst = $.data(cur[j], 'sortable');
1711 if(inst && inst != this && !inst.options.disabled) {
1712 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
1713 this.containers.push(inst);
1714 }
1715 };
1716 };
1717 }
1718
1719 for (var i = queries.length - 1; i >= 0; i--) {
1720 var targetData = queries[i][1];
1721 var _queries = queries[i][0];
1722
1723 for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) {
1724 var item = $(_queries[j]);
1725
1726 item.data('sortable-item', targetData); // Data for target checking (mouse manager)
1727
1728 items.push({
1729 item: item,
1730 instance: targetData,
1731 width: 0, height: 0,
1732 left: 0, top: 0
1733 });
1734 };
1735 };
1736
1737 },
1738
1739 refreshPositions: function(fast) {
1740
1741 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
1742 if(this.offsetParent && this.helper) {
1743 this.offset.parent = this._getParentOffset();
1744 }
1745
1746 for (var i = this.items.length - 1; i >= 0; i--){
1747 var item = this.items[i];
1748
1749 //We ignore calculating positions of all connected containers when we're not over them
1750 if(item.instance != this.currentContainer && this.currentContainer && item.item[0] != this.currentItem[0])
1751 continue;
1752
1753 var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
1754
1755 if (!fast) {
1756 if (this.options.accurateIntersection) {
1757 item.width = t.outerWidth();
1758 item.height = t.outerHeight();
1759 }
1760 else {
1761 item.width = t[0].offsetWidth;
1762 item.height = t[0].offsetHeight;
1763 }
1764 }
1765
1766 var p = t.offset();
1767 item.left = p.left;
1768 item.top = p.top;
1769 };
1770
1771 if(this.options.custom && this.options.custom.refreshContainers) {
1772 this.options.custom.refreshContainers.call(this);
1773 } else {
1774 for (var i = this.containers.length - 1; i >= 0; i--){
1775 var p = this.containers[i].element.offset();
1776 this.containers[i].containerCache.left = p.left;
1777 this.containers[i].containerCache.top = p.top;
1778 this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
1779 this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
1780 };
1781 }
1782
1783 },
1784
1785 _createPlaceholder: function(that) {
1786
1787 var self = that || this, o = self.options;
1788
1789 if(!o.placeholder || o.placeholder.constructor == String) {
1790 var className = o.placeholder;
1791 o.placeholder = {
1792 element: function() {
1793
1794 var el = $(document.createElement(self.currentItem[0].nodeName))
1795 .addClass(className || self.currentItem[0].className+" ui-sortable-placeholder")
1796 .removeClass('ui-sortable-helper')[0];
1797
1798 if(!className) {
1799 el.style.visibility = "hidden";
1800 document.body.appendChild(el);
1801 // Name attributes are removed, otherwice causes elements to be unchecked
1802 // Expando attributes also have to be removed because of stupid IE (no condition, doesn't hurt in other browsers)
1803 el.innerHTML = self.currentItem[0].innerHTML.replace(/name\=\"[^\"\']+\"/g, '').replace(/jQuery[0-9]+\=\"[^\"\']+\"/g, '');
1804 document.body.removeChild(el);
1805 };
1806
1807 return el;
1808 },
1809 update: function(container, p) {
1810 if(className && !o.forcePlaceholderSize) return;
1811 if(!p.height()) { p.height(self.currentItem.innerHeight() - parseInt(self.currentItem.css('paddingTop')||0, 10) - parseInt(self.currentItem.css('paddingBottom')||0, 10)); };
1812 if(!p.width()) { p.width(self.currentItem.innerWidth() - parseInt(self.currentItem.css('paddingLeft')||0, 10) - parseInt(self.currentItem.css('paddingRight')||0, 10)); };
1813 }
1814 };
1815 }
1816
1817 //Create the placeholder
1818 self.placeholder = $(o.placeholder.element.call(self.element, self.currentItem));
1819
1820 //Append it after the actual current item
1821 self.currentItem.after(self.placeholder);
1822
1823 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
1824 o.placeholder.update(self, self.placeholder);
1825
1826 },
1827
1828 _contactContainers: function(event) {
1829 for (var i = this.containers.length - 1; i >= 0; i--){
1830
1831 if(this._intersectsWith(this.containers[i].containerCache)) {
1832 if(!this.containers[i].containerCache.over) {
1833
1834 if(this.currentContainer != this.containers[i]) {
1835
1836 //When entering a new container, we will find the item with the least distance and append our item near it
1837 var dist = 10000; var itemWithLeastDistance = null; var base = this.positionAbs[this.containers[i].floating ? 'left' : 'top'];
1838 for (var j = this.items.length - 1; j >= 0; j--) {
1839 if(!$.ui.contains(this.containers[i].element[0], this.items[j].item[0])) continue;
1840 var cur = this.items[j][this.containers[i].floating ? 'left' : 'top'];
1841 if(Math.abs(cur - base) < dist) {
1842 dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];
1843 }
1844 }
1845
1846 if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled
1847 continue;
1848
1849 this.currentContainer = this.containers[i];
1850 itemWithLeastDistance ? this.options.sortIndicator.call(this, event, itemWithLeastDistance, null, true) : this.options.sortIndicator.call(this, event, null, this.containers[i].element, true);
1851 this._propagate("change", event); //Call plugins and callbacks
1852 this.containers[i]._propagate("change", event, this); //Call plugins and callbacks
1853
1854 //Update the placeholder
1855 this.options.placeholder.update(this.currentContainer, this.placeholder);
1856
1857 }
1858
1859 this.containers[i]._propagate("over", event, this);
1860 this.containers[i].containerCache.over = 1;
1861 }
1862 } else {
1863 if(this.containers[i].containerCache.over) {
1864 this.containers[i]._propagate("out", event, this);
1865 this.containers[i].containerCache.over = 0;
1866 }
1867 }
1868
1869 };
1870 },
1871
1872 _createHelper: function(event) {
1873
1874 var o = this.options;
1875 var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem);
1876
1877 if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already
1878 $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
1879
1880 if(helper[0] == this.currentItem[0])
1881 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") };
1882
1883 if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width());
1884 if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height());
1885
1886 return helper;
1887
1888 },
1889
1890 _adjustOffsetFromHelper: function(obj) {
1891 if(obj.left != undefined) this.offset.click.left = obj.left + this.margins.left;
1892 if(obj.right != undefined) this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
1893 if(obj.top != undefined) this.offset.click.top = obj.top + this.margins.top;
1894 if(obj.bottom != undefined) this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
1895 },
1896
1897 _getParentOffset: function() {
1898
1899 //Get the offsetParent and cache its position
1900 this.offsetParent = this.helper.offsetParent(); var po = this.offsetParent.offset();
1901
1902 if((this.offsetParent[0] == document.body && $.browser.mozilla) //Ugly FF3 fix
1903 || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix
1904 po = { top: 0, left: 0 };
1905
1906 return {
1907 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
1908 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
1909 };
1910
1911 },
1912
1913 _getRelativeOffset: function() {
1914
1915 if(this.cssPosition == "relative") {
1916 var p = this.currentItem.position();
1917 return {
1918 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
1919 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
1920 };
1921 } else {
1922 return { top: 0, left: 0 };
1923 }
1924
1925 },
1926
1927 _cacheMargins: function() {
1928 this.margins = {
1929 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
1930 top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
1931 };
1932 },
1933
1934 _cacheHelperProportions: function() {
1935 this.helperProportions = {
1936 width: this.helper.outerWidth(),
1937 height: this.helper.outerHeight()
1938 };
1939 },
1940
1941 _setContainment: function() {
1942
1943 var o = this.options;
1944 if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
1945 if(o.containment == 'document' || o.containment == 'window') this.containment = [
1946 0 - this.offset.relative.left - this.offset.parent.left,
1947 0 - this.offset.relative.top - this.offset.parent.top,
1948 $(o.containment == 'document' ? document : window).width() - this.offset.relative.left - this.offset.parent.left - this.margins.left - (parseInt(this.currentItem.css("marginRight"),10) || 0),
1949 ($(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)
1950 ];
1951
1952 if(!(/^(document|window|parent)$/).test(o.containment)) {
1953 var ce = $(o.containment)[0];
1954 var co = $(o.containment).offset();
1955 var over = ($(ce).css("overflow") != 'hidden');
1956
1957 this.containment = [
1958 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) - this.offset.relative.left - this.offset.parent.left - this.margins.left,
1959 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) - this.offset.relative.top - this.offset.parent.top - this.margins.top,
1960 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,
1961 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
1962 ];
1963 }
1964
1965 },
1966
1967 _convertPositionTo: function(d, pos) {
1968
1969 if(!pos) pos = this.position;
1970 var mod = d == "absolute" ? 1 : -1;
1971 var scroll = this[(this.cssPosition == 'absolute' ? 'offset' : 'scroll')+'Parent'], scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
1972
1973 return {
1974 top: (
1975 pos.top // the calculated relative position
1976 + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent
1977 + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border)
1978 + ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod
1979 + this.margins.top * mod //Add the margin (you don't want the margin counting in intersection methods)
1980 ),
1981 left: (
1982 pos.left // the calculated relative position
1983 + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent
1984 + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border)
1985 + ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : ( scrollIsRootNode ? 0 : scroll.scrollLeft() ) ) * mod
1986 + this.margins.left * mod //Add the margin (you don't want the margin counting in intersection methods)
1987 )
1988 };
1989 },
1990
1991 _generatePosition: function(event) {
1992
1993 var o = this.options, scroll = this[(this.cssPosition == 'absolute' ? 'offset' : 'scroll')+'Parent'], scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
1994
1995 var position = {
1996 top: (
1997 event.pageY // The absolute mouse position
1998 - this.offset.click.top // Click offset (relative to the element)
1999 - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent
2000 - this.offset.parent.top // The offsetParent's offset without borders (offset + border)
2001 + ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )
2002 ),
2003 left: (
2004 event.pageX // The absolute mouse position
2005 - this.offset.click.left // Click offset (relative to the element)
2006 - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent
2007 - this.offset.parent.left // The offsetParent's offset without borders (offset + border)
2008 + ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : ( scrollIsRootNode ? 0 : scroll.scrollLeft() ) )
2009 )
2010 };
2011
2012 if(!this.originalPosition) return position; //If we are not dragging yet, we won't check for options
2013
2014 /*
2015 * - Position constraining -
2016 * Constrain the position to a mix of grid, containment.
2017 */
2018 if(this.containment) {
2019 if(position.left < this.containment[0]) position.left = this.containment[0];
2020 if(position.top < this.containment[1]) position.top = this.containment[1];
2021 if(position.left + this.helperProportions.width > this.containment[2]) position.left = this.containment[2] - this.helperProportions.width;
2022 if(position.top + this.helperProportions.height > this.containment[3]) position.top = this.containment[3] - this.helperProportions.height;
2023 }
2024
2025 if(o.grid) {
2026 var top = this.originalPosition.top + Math.round((position.top - this.originalPosition.top) / o.grid[1]) * o.grid[1];
2027 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;
2028
2029 var left = this.originalPosition.left + Math.round((position.left - this.originalPosition.left) / o.grid[0]) * o.grid[0];
2030 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;
2031 }
2032
2033 return position;
2034 },
2035
2036 _rearrange: function(event, i, a, hardRefresh) {
2037
2038 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));
2039
2040 //Various things done here to improve the performance:
2041 // 1. we create a setTimeout, that calls refreshPositions
2042 // 2. on the instance, we have a counter variable, that get's higher after every append
2043 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
2044 // 4. this lets only the last addition to the timeout stack through
2045 this.counter = this.counter ? ++this.counter : 1;
2046 var self = this, counter = this.counter;
2047
2048 window.setTimeout(function() {
2049 if(counter == self.counter) self.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
2050 },0);
2051
2052 },
2053
2054 _clear: function(event, noPropagation) {
2055
2056 this.reverting = false;
2057
2058 //We first have to update the dom position of the actual currentItem
2059 if(!this._noFinalSort) this.placeholder.before(this.currentItem);
2060 this._noFinalSort = null;
2061
2062 if(this.helper[0] == this.currentItem[0]) {
2063 for(var i in this._storedCSS) {
2064 if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = '';
2065 }
2066 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
2067 } else {
2068 this.currentItem.show();
2069 }
2070
2071 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
2072 if(!$.ui.contains(this.element[0], this.currentItem[0])) { //Node was moved out of the current element
2073 this._propagate("remove", event, null, noPropagation);
2074 for (var i = this.containers.length - 1; i >= 0; i--){
2075 if($.ui.contains(this.containers[i].element[0], this.currentItem[0])) {
2076 this.containers[i]._propagate("update", event, this, noPropagation);
2077 this.containers[i]._propagate("receive", event, this, noPropagation);
2078 }
2079 };
2080 };
2081
2082 //Post events to containers
2083 for (var i = this.containers.length - 1; i >= 0; i--){
2084 this.containers[i]._propagate("deactivate", event, this, noPropagation);
2085 if(this.containers[i].containerCache.over) {
2086 this.containers[i]._propagate("out", event, this);
2087 this.containers[i].containerCache.over = 0;
2088 }
2089 }
2090
2091 this.dragging = false;
2092 if(this.cancelHelperRemoval) {
2093 this._propagate("beforeStop", event, null, noPropagation);
2094 this._propagate("stop", event, null, noPropagation);
2095 return false;
2096 }
2097
2098 this._propagate("beforeStop", event, null, noPropagation);
2099
2100 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
2101 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
2102
2103 if(this.options.helper != "original") this.helper.remove(); this.helper = null;
2104 this._propagate("stop", event, null, noPropagation);
2105
2106 return true;
2107
2108 },
2109
2110 _propagate: function(n, event, inst, noPropagation) {
2111 $.ui.plugin.call(this, n, [event, this._ui(inst)]);
2112 var dontCancel = !noPropagation ? this.element.triggerHandler(n == "sort" ? n : "sort"+n, [event, this._ui(inst)], this.options[n]) : true;
2113 if(dontCancel === false) this.cancel();
2114 },
2115
2116 plugins: {},
2117
2118 _ui: function(inst) {
2119 var self = inst || this;
2120 return {
2121 helper: self.helper,
2122 placeholder: self.placeholder || $([]),
2123 position: self.position,
2124 absolutePosition: self.positionAbs,
2125 item: self.currentItem,
2126 sender: inst ? inst.element : null
2127 };
2128 }
2129
2130 }));
2131
2132 $.extend($.ui.sortable, {
2133 getter: "serialize toArray",
2134 version: "1.6",
2135 defaults: {
2136 accurateIntersection: true,
2137 appendTo: "parent",
2138 cancel: ":input",
2139 delay: 0,
2140 distance: 1,
2141 dropOnEmpty: true,
2142 forcePlaceholderSize: false,
2143 forceHelperSize: false,
2144 helper: "original",
2145 items: '> *',
2146 scope: "default",
2147 scroll: true,
2148 scrollSensitivity: 20,
2149 scrollSpeed: 20,
2150 sortIndicator: $.ui.sortable.prototype._rearrange,
2151 tolerance: "default",
2152 zIndex: 1000
2153 }
2154 });
2155
2156 /*
2157 * Sortable Extensions
2158 */
2159
2160 $.ui.plugin.add("sortable", "cursor", {
2161 start: function(event, ui) {
2162 var t = $('body'), i = $(this).data('sortable');
2163 if (t.css("cursor")) i.options._cursor = t.css("cursor");
2164 t.css("cursor", i.options.cursor);
2165 },
2166 beforeStop: function(event, ui) {
2167 var i = $(this).data('sortable');
2168 if (i.options._cursor) $('body').css("cursor", i.options._cursor);
2169 }
2170 });
2171
2172 $.ui.plugin.add("sortable", "opacity", {
2173 start: function(event, ui) {
2174 var t = ui.helper, i = $(this).data('sortable');
2175 if(t.css("opacity")) i.options._opacity = t.css("opacity");
2176 t.css('opacity', i.options.opacity);
2177 },
2178 beforeStop: function(event, ui) {
2179 var i = $(this).data('sortable');
2180 if(i.options._opacity) $(ui.helper).css('opacity', i.options._opacity);
2181 }
2182 });
2183
2184 $.ui.plugin.add("sortable", "scroll", {
2185 start: function(event, ui) {
2186 var i = $(this).data("sortable"), o = i.options;
2187 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset();
2188 },
2189 sort: function(event, ui) {
2190
2191 var i = $(this).data("sortable"), o = i.options, scrolled = false;
2192
2193 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') {
2194
2195 if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
2196 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
2197 else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity)
2198 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
2199
2200 if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
2201 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
2202 else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity)
2203 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
2204
2205 } else {
2206
2207 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
2208 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
2209 else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
2210 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
2211
2212 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
2213 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
2214 else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
2215 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
2216
2217 }
2218
2219 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
2220 $.ui.ddmanager.prepareOffsets(i, event);
2221
2222
2223
2224 //This is a special case where we need to modify a offset calculated on start, since the following happened:
2225 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
2226 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
2227 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
2228 if(scrolled !== false && i.cssPosition == 'absolute' && i.scrollParent[0] != document && $.ui.contains(i.scrollParent[0], i.offsetParent[0])) {
2229 i.offset.parent = i._getParentOffset();
2230 }
2231
2232 // This is another very weird special case that only happens for relative elements:
2233 // 1. If the css position is relative
2234 // 2. and the scroll parent is the document or similar to the offset parent
2235 // we have to refresh the relative offset during the scroll so there are no jumps
2236 if(scrolled !== false && i.cssPosition == 'relative' && !(i.scrollParent[0] != document && i.scrollParent[0] != i.offsetParent[0])) {
2237 i.offset.relative = i._getRelativeOffset();
2238 }
2239
2240 }
2241 });
2242
2243 $.ui.plugin.add("sortable", "zIndex", {
2244 start: function(event, ui) {
2245 var t = ui.helper, i = $(this).data('sortable');
2246 if(t.css("zIndex")) i.options._zIndex = t.css("zIndex");
2247 t.css('zIndex', i.options.zIndex);
2248 },
2249 beforeStop: function(event, ui) {
2250 var i = $(this).data('sortable');
2251 if(i.options._zIndex) $(ui.helper).css('zIndex', i.options._zIndex == 'auto' ? '' : i.options._zIndex);
2252 }
2253 });
2254
2255 })(jQuery);