1 | /* |
---|
2 | * jQuery UI Draggable |
---|
3 | * |
---|
4 | * Copyright (c) 2008 Paul Bakaus |
---|
5 | * Dual licensed under the MIT (MIT-LICENSE.txt) |
---|
6 | * and GPL (GPL-LICENSE.txt) licenses. |
---|
7 | * |
---|
8 | * http://docs.jquery.com/UI/Draggables |
---|
9 | * |
---|
10 | * Depends: |
---|
11 | * ui.core.js |
---|
12 | */ |
---|
13 | (function($) { |
---|
14 | |
---|
15 | $.widget("ui.draggable", $.extend({}, $.ui.mouse, { |
---|
16 | init: function() { |
---|
17 | |
---|
18 | //Initialize needed constants |
---|
19 | var o = this.options; |
---|
20 | |
---|
21 | //Position the node |
---|
22 | if (o.helper == 'original' && !(/(relative|absolute|fixed)/).test(this.element.css('position'))) |
---|
23 | this.element.css('position', 'relative'); |
---|
24 | |
---|
25 | this.element.addClass('ui-draggable'); |
---|
26 | (o.disabled && this.element.addClass('ui-draggable-disabled')); |
---|
27 | |
---|
28 | this.mouseInit(); |
---|
29 | |
---|
30 | }, |
---|
31 | mouseStart: function(e) { |
---|
32 | var o = this.options; |
---|
33 | |
---|
34 | if (this.helper || o.disabled || $(e.target).is('.ui-resizable-handle')) return false; |
---|
35 | |
---|
36 | var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false; |
---|
37 | |
---|
38 | |
---|
39 | $(this.options.handle, this.element).find("*").andSelf().each(function() { |
---|
40 | if(this == e.target) handle = true; |
---|
41 | }); |
---|
42 | if (!handle) return false; |
---|
43 | |
---|
44 | if($.ui.ddmanager) $.ui.ddmanager.current = this; |
---|
45 | |
---|
46 | //Create and append the visible helper |
---|
47 | this.helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [e])) : (o.helper == 'clone' ? this.element.clone() : this.element); |
---|
48 | if(!this.helper.parents('body').length) this.helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo)); |
---|
49 | if(this.helper[0] != this.element[0] && !(/(fixed|absolute)/).test(this.helper.css("position"))) this.helper.css("position", "absolute"); |
---|
50 | |
---|
51 | /* |
---|
52 | * - Position generation - |
---|
53 | * This block generates everything position related - it's the core of draggables. |
---|
54 | */ |
---|
55 | |
---|
56 | this.margins = { //Cache the margins |
---|
57 | left: (parseInt(this.element.css("marginLeft"),10) || 0), |
---|
58 | top: (parseInt(this.element.css("marginTop"),10) || 0) |
---|
59 | }; |
---|
60 | |
---|
61 | this.cssPosition = this.helper.css("position"); //Store the helper's css position |
---|
62 | this.offset = this.element.offset(); //The element's absolute position on the page |
---|
63 | this.offset = { //Substract the margins from the element's absolute offset |
---|
64 | top: this.offset.top - this.margins.top, |
---|
65 | left: this.offset.left - this.margins.left |
---|
66 | }; |
---|
67 | |
---|
68 | this.offset.click = { //Where the click happened, relative to the element |
---|
69 | left: e.pageX - this.offset.left, |
---|
70 | top: e.pageY - this.offset.top |
---|
71 | }; |
---|
72 | |
---|
73 | this.offsetParent = this.helper.offsetParent(); var po = this.offsetParent.offset(); //Get the offsetParent and cache its position |
---|
74 | if(this.offsetParent[0] == document.body && $.browser.mozilla) po = { top: 0, left: 0 }; //Ugly FF3 fix |
---|
75 | this.offset.parent = { //Store its position plus border |
---|
76 | top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), |
---|
77 | left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) |
---|
78 | }; |
---|
79 | |
---|
80 | var p = this.element.position(); //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helpers |
---|
81 | this.offset.relative = this.cssPosition == "relative" ? { |
---|
82 | top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.offsetParent[0].scrollTop, |
---|
83 | left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.offsetParent[0].scrollLeft |
---|
84 | } : { top: 0, left: 0 }; |
---|
85 | |
---|
86 | this.originalPosition = this.generatePosition(e); //Generate the original position |
---|
87 | this.helperProportions = { width: this.helper.outerWidth(), height: this.helper.outerHeight() };//Cache the helper size |
---|
88 | |
---|
89 | if(o.cursorAt) { |
---|
90 | if(o.cursorAt.left != undefined) this.offset.click.left = o.cursorAt.left + this.margins.left; |
---|
91 | if(o.cursorAt.right != undefined) this.offset.click.left = this.helperProportions.width - o.cursorAt.right + this.margins.left; |
---|
92 | if(o.cursorAt.top != undefined) this.offset.click.top = o.cursorAt.top + this.margins.top; |
---|
93 | if(o.cursorAt.bottom != undefined) this.offset.click.top = this.helperProportions.height - o.cursorAt.bottom + this.margins.top; |
---|
94 | } |
---|
95 | |
---|
96 | |
---|
97 | /* |
---|
98 | * - Position constraining - |
---|
99 | * Here we prepare position constraining like grid and containment. |
---|
100 | */ |
---|
101 | |
---|
102 | if(o.containment) { |
---|
103 | if(o.containment == 'parent') o.containment = this.helper[0].parentNode; |
---|
104 | if(o.containment == 'document' || o.containment == 'window') this.containment = [ |
---|
105 | 0 - this.offset.relative.left - this.offset.parent.left, |
---|
106 | 0 - this.offset.relative.top - this.offset.parent.top, |
---|
107 | $(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), |
---|
108 | ($(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) |
---|
109 | ]; |
---|
110 | |
---|
111 | if(!(/^(document|window|parent)$/).test(o.containment)) { |
---|
112 | var ce = $(o.containment)[0]; |
---|
113 | var co = $(o.containment).offset(); |
---|
114 | |
---|
115 | this.containment = [ |
---|
116 | co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) - this.offset.relative.left - this.offset.parent.left, |
---|
117 | co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) - this.offset.relative.top - this.offset.parent.top, |
---|
118 | co.left+Math.max(ce.scrollWidth,ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - this.offset.relative.left - this.offset.parent.left - this.helperProportions.width - this.margins.left - (parseInt(this.element.css("marginRight"),10) || 0), |
---|
119 | co.top+Math.max(ce.scrollHeight,ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - this.offset.relative.top - this.offset.parent.top - this.helperProportions.height - this.margins.top - (parseInt(this.element.css("marginBottom"),10) || 0) |
---|
120 | ]; |
---|
121 | } |
---|
122 | } |
---|
123 | |
---|
124 | //Call plugins and callbacks |
---|
125 | this.propagate("start", e); |
---|
126 | |
---|
127 | this.helperProportions = { width: this.helper.outerWidth(), height: this.helper.outerHeight() };//Recache the helper size |
---|
128 | if ($.ui.ddmanager && !o.dropBehaviour) $.ui.ddmanager.prepareOffsets(this, e); |
---|
129 | |
---|
130 | this.helper.addClass("ui-draggable-dragging"); |
---|
131 | this.mouseDrag(e); //Execute the drag once - this causes the helper not to be visible before getting its correct position |
---|
132 | return true; |
---|
133 | }, |
---|
134 | convertPositionTo: function(d, pos) { |
---|
135 | if(!pos) pos = this.position; |
---|
136 | var mod = d == "absolute" ? 1 : -1; |
---|
137 | return { |
---|
138 | top: ( |
---|
139 | pos.top // the calculated relative position |
---|
140 | + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent |
---|
141 | + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) |
---|
142 | - (this.cssPosition == "fixed" || (this.cssPosition == "absolute" && this.offsetParent[0] == document.body) ? 0 : this.offsetParent[0].scrollTop) * mod // The offsetParent's scroll position, not if the element is fixed |
---|
143 | + (this.cssPosition == "fixed" ? $(document).scrollTop() : 0) * mod |
---|
144 | + this.margins.top * mod //Add the margin (you don't want the margin counting in intersection methods) |
---|
145 | ), |
---|
146 | left: ( |
---|
147 | pos.left // the calculated relative position |
---|
148 | + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent |
---|
149 | + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) |
---|
150 | - (this.cssPosition == "fixed" || (this.cssPosition == "absolute" && this.offsetParent[0] == document.body) ? 0 : this.offsetParent[0].scrollLeft) * mod // The offsetParent's scroll position, not if the element is fixed |
---|
151 | + (this.cssPosition == "fixed" ? $(document).scrollLeft() : 0) * mod |
---|
152 | + this.margins.left * mod //Add the margin (you don't want the margin counting in intersection methods) |
---|
153 | ) |
---|
154 | }; |
---|
155 | }, |
---|
156 | generatePosition: function(e) { |
---|
157 | |
---|
158 | var o = this.options; |
---|
159 | var position = { |
---|
160 | top: ( |
---|
161 | e.pageY // The absolute mouse position |
---|
162 | - this.offset.click.top // Click offset (relative to the element) |
---|
163 | - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent |
---|
164 | - this.offset.parent.top // The offsetParent's offset without borders (offset + border) |
---|
165 | + (this.cssPosition == "fixed" || (this.cssPosition == "absolute" && this.offsetParent[0] == document.body) ? 0 : this.offsetParent[0].scrollTop) // The offsetParent's scroll position, not if the element is fixed |
---|
166 | - (this.cssPosition == "fixed" ? $(document).scrollTop() : 0) |
---|
167 | ), |
---|
168 | left: ( |
---|
169 | e.pageX // The absolute mouse position |
---|
170 | - this.offset.click.left // Click offset (relative to the element) |
---|
171 | - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent |
---|
172 | - this.offset.parent.left // The offsetParent's offset without borders (offset + border) |
---|
173 | + (this.cssPosition == "fixed" || (this.cssPosition == "absolute" && this.offsetParent[0] == document.body) ? 0 : this.offsetParent[0].scrollLeft) // The offsetParent's scroll position, not if the element is fixed |
---|
174 | - (this.cssPosition == "fixed" ? $(document).scrollLeft() : 0) |
---|
175 | ) |
---|
176 | }; |
---|
177 | |
---|
178 | if(!this.originalPosition) return position; //If we are not dragging yet, we won't check for options |
---|
179 | |
---|
180 | /* |
---|
181 | * - Position constraining - |
---|
182 | * Constrain the position to a mix of grid, containment. |
---|
183 | */ |
---|
184 | if(this.containment) { |
---|
185 | if(position.left < this.containment[0]) position.left = this.containment[0]; |
---|
186 | if(position.top < this.containment[1]) position.top = this.containment[1]; |
---|
187 | if(position.left > this.containment[2]) position.left = this.containment[2]; |
---|
188 | if(position.top > this.containment[3]) position.top = this.containment[3]; |
---|
189 | } |
---|
190 | |
---|
191 | if(o.grid) { |
---|
192 | var top = this.originalPosition.top + Math.round((position.top - this.originalPosition.top) / o.grid[1]) * o.grid[1]; |
---|
193 | 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; |
---|
194 | |
---|
195 | var left = this.originalPosition.left + Math.round((position.left - this.originalPosition.left) / o.grid[0]) * o.grid[0]; |
---|
196 | 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; |
---|
197 | } |
---|
198 | |
---|
199 | return position; |
---|
200 | }, |
---|
201 | mouseDrag: function(e) { |
---|
202 | |
---|
203 | //Compute the helpers position |
---|
204 | this.position = this.generatePosition(e); |
---|
205 | this.positionAbs = this.convertPositionTo("absolute"); |
---|
206 | |
---|
207 | //Call plugins and callbacks and use the resulting position if something is returned |
---|
208 | this.position = this.propagate("drag", e) || this.position; |
---|
209 | |
---|
210 | if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; |
---|
211 | if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; |
---|
212 | if($.ui.ddmanager) $.ui.ddmanager.drag(this, e); |
---|
213 | |
---|
214 | return false; |
---|
215 | }, |
---|
216 | mouseStop: function(e) { |
---|
217 | |
---|
218 | //If we are using droppables, inform the manager about the drop |
---|
219 | var dropped = false; |
---|
220 | if ($.ui.ddmanager && !this.options.dropBehaviour) |
---|
221 | var dropped = $.ui.ddmanager.drop(this, e); |
---|
222 | |
---|
223 | if((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true) { |
---|
224 | var self = this; |
---|
225 | $(this.helper).animate(this.originalPosition, parseInt(this.options.revert, 10) || 500, function() { |
---|
226 | self.propagate("stop", e); |
---|
227 | self.clear(); |
---|
228 | }); |
---|
229 | } else { |
---|
230 | this.propagate("stop", e); |
---|
231 | this.clear(); |
---|
232 | } |
---|
233 | |
---|
234 | return false; |
---|
235 | }, |
---|
236 | clear: function() { |
---|
237 | this.helper.removeClass("ui-draggable-dragging"); |
---|
238 | if(this.options.helper != 'original' && !this.cancelHelperRemoval) this.helper.remove(); |
---|
239 | //if($.ui.ddmanager) $.ui.ddmanager.current = null; |
---|
240 | this.helper = null; |
---|
241 | this.cancelHelperRemoval = false; |
---|
242 | }, |
---|
243 | |
---|
244 | // From now on bulk stuff - mainly helpers |
---|
245 | plugins: {}, |
---|
246 | uiHash: function(e) { |
---|
247 | return { |
---|
248 | helper: this.helper, |
---|
249 | position: this.position, |
---|
250 | absolutePosition: this.positionAbs, |
---|
251 | options: this.options |
---|
252 | }; |
---|
253 | }, |
---|
254 | propagate: function(n,e) { |
---|
255 | $.ui.plugin.call(this, n, [e, this.uiHash()]); |
---|
256 | if(n == "drag") this.positionAbs = this.convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins |
---|
257 | return this.element.triggerHandler(n == "drag" ? n : "drag"+n, [e, this.uiHash()], this.options[n]); |
---|
258 | }, |
---|
259 | destroy: function() { |
---|
260 | if(!this.element.data('draggable')) return; |
---|
261 | this.element.removeData("draggable").unbind(".draggable").removeClass('ui-draggable'); |
---|
262 | this.mouseDestroy(); |
---|
263 | } |
---|
264 | })); |
---|
265 | |
---|
266 | $.extend($.ui.draggable, { |
---|
267 | defaults: { |
---|
268 | appendTo: "parent", |
---|
269 | axis: false, |
---|
270 | cancel: ":input", |
---|
271 | delay: 0, |
---|
272 | distance: 1, |
---|
273 | helper: "original" |
---|
274 | } |
---|
275 | }); |
---|
276 | |
---|
277 | $.ui.plugin.add("draggable", "cursor", { |
---|
278 | start: function(e, ui) { |
---|
279 | var t = $('body'); |
---|
280 | if (t.css("cursor")) ui.options._cursor = t.css("cursor"); |
---|
281 | t.css("cursor", ui.options.cursor); |
---|
282 | }, |
---|
283 | stop: function(e, ui) { |
---|
284 | if (ui.options._cursor) $('body').css("cursor", ui.options._cursor); |
---|
285 | } |
---|
286 | }); |
---|
287 | |
---|
288 | $.ui.plugin.add("draggable", "zIndex", { |
---|
289 | start: function(e, ui) { |
---|
290 | var t = $(ui.helper); |
---|
291 | if(t.css("zIndex")) ui.options._zIndex = t.css("zIndex"); |
---|
292 | t.css('zIndex', ui.options.zIndex); |
---|
293 | }, |
---|
294 | stop: function(e, ui) { |
---|
295 | if(ui.options._zIndex) $(ui.helper).css('zIndex', ui.options._zIndex); |
---|
296 | } |
---|
297 | }); |
---|
298 | |
---|
299 | $.ui.plugin.add("draggable", "opacity", { |
---|
300 | start: function(e, ui) { |
---|
301 | var t = $(ui.helper); |
---|
302 | if(t.css("opacity")) ui.options._opacity = t.css("opacity"); |
---|
303 | t.css('opacity', ui.options.opacity); |
---|
304 | }, |
---|
305 | stop: function(e, ui) { |
---|
306 | if(ui.options._opacity) $(ui.helper).css('opacity', ui.options._opacity); |
---|
307 | } |
---|
308 | }); |
---|
309 | |
---|
310 | $.ui.plugin.add("draggable", "iframeFix", { |
---|
311 | start: function(e, ui) { |
---|
312 | $(ui.options.iframeFix === true ? "iframe" : ui.options.iframeFix).each(function() { |
---|
313 | $('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>') |
---|
314 | .css({ |
---|
315 | width: this.offsetWidth+"px", height: this.offsetHeight+"px", |
---|
316 | position: "absolute", opacity: "0.001", zIndex: 1000 |
---|
317 | }) |
---|
318 | .css($(this).offset()) |
---|
319 | .appendTo("body"); |
---|
320 | }); |
---|
321 | }, |
---|
322 | stop: function(e, ui) { |
---|
323 | $("div.DragDropIframeFix").each(function() { this.parentNode.removeChild(this); }); //Remove frame helpers |
---|
324 | } |
---|
325 | }); |
---|
326 | |
---|
327 | $.ui.plugin.add("draggable", "scroll", { |
---|
328 | start: function(e, ui) { |
---|
329 | var o = ui.options; |
---|
330 | var i = $(this).data("draggable"); |
---|
331 | o.scrollSensitivity = o.scrollSensitivity || 20; |
---|
332 | o.scrollSpeed = o.scrollSpeed || 20; |
---|
333 | |
---|
334 | i.overflowY = function(el) { |
---|
335 | do { if(/auto|scroll/.test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-y'))) return el; el = el.parent(); } while (el[0].parentNode); |
---|
336 | return $(document); |
---|
337 | }(this); |
---|
338 | i.overflowX = function(el) { |
---|
339 | do { if(/auto|scroll/.test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-x'))) return el; el = el.parent(); } while (el[0].parentNode); |
---|
340 | return $(document); |
---|
341 | }(this); |
---|
342 | |
---|
343 | if(i.overflowY[0] != document && i.overflowY[0].tagName != 'HTML') i.overflowYOffset = i.overflowY.offset(); |
---|
344 | if(i.overflowX[0] != document && i.overflowX[0].tagName != 'HTML') i.overflowXOffset = i.overflowX.offset(); |
---|
345 | |
---|
346 | }, |
---|
347 | drag: function(e, ui) { |
---|
348 | |
---|
349 | var o = ui.options; |
---|
350 | var i = $(this).data("draggable"); |
---|
351 | |
---|
352 | if(i.overflowY[0] != document && i.overflowY[0].tagName != 'HTML') { |
---|
353 | if((i.overflowYOffset.top + i.overflowY[0].offsetHeight) - e.pageY < o.scrollSensitivity) |
---|
354 | i.overflowY[0].scrollTop = i.overflowY[0].scrollTop + o.scrollSpeed; |
---|
355 | if(e.pageY - i.overflowYOffset.top < o.scrollSensitivity) |
---|
356 | i.overflowY[0].scrollTop = i.overflowY[0].scrollTop - o.scrollSpeed; |
---|
357 | |
---|
358 | } else { |
---|
359 | if(e.pageY - $(document).scrollTop() < o.scrollSensitivity) |
---|
360 | $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); |
---|
361 | if($(window).height() - (e.pageY - $(document).scrollTop()) < o.scrollSensitivity) |
---|
362 | $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); |
---|
363 | } |
---|
364 | |
---|
365 | if(i.overflowX[0] != document && i.overflowX[0].tagName != 'HTML') { |
---|
366 | if((i.overflowXOffset.left + i.overflowX[0].offsetWidth) - e.pageX < o.scrollSensitivity) |
---|
367 | i.overflowX[0].scrollLeft = i.overflowX[0].scrollLeft + o.scrollSpeed; |
---|
368 | if(e.pageX - i.overflowXOffset.left < o.scrollSensitivity) |
---|
369 | i.overflowX[0].scrollLeft = i.overflowX[0].scrollLeft - o.scrollSpeed; |
---|
370 | } else { |
---|
371 | if(e.pageX - $(document).scrollLeft() < o.scrollSensitivity) |
---|
372 | $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); |
---|
373 | if($(window).width() - (e.pageX - $(document).scrollLeft()) < o.scrollSensitivity) |
---|
374 | $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); |
---|
375 | } |
---|
376 | |
---|
377 | } |
---|
378 | }); |
---|
379 | |
---|
380 | $.ui.plugin.add("draggable", "snap", { |
---|
381 | start: function(e, ui) { |
---|
382 | |
---|
383 | var inst = $(this).data("draggable"); |
---|
384 | inst.snapElements = []; |
---|
385 | $(ui.options.snap === true ? '.ui-draggable' : ui.options.snap).each(function() { |
---|
386 | var $t = $(this); var $o = $t.offset(); |
---|
387 | if(this != inst.element[0]) inst.snapElements.push({ |
---|
388 | item: this, |
---|
389 | width: $t.outerWidth(), height: $t.outerHeight(), |
---|
390 | top: $o.top, left: $o.left |
---|
391 | }); |
---|
392 | }); |
---|
393 | |
---|
394 | }, |
---|
395 | drag: function(e, ui) { |
---|
396 | |
---|
397 | var inst = $(this).data("draggable"); |
---|
398 | var d = ui.options.snapTolerance || 20; |
---|
399 | var x1 = ui.absolutePosition.left, x2 = x1 + inst.helperProportions.width, |
---|
400 | y1 = ui.absolutePosition.top, y2 = y1 + inst.helperProportions.height; |
---|
401 | |
---|
402 | for (var i = inst.snapElements.length - 1; i >= 0; i--){ |
---|
403 | |
---|
404 | var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width, |
---|
405 | t = inst.snapElements[i].top, b = t + inst.snapElements[i].height; |
---|
406 | |
---|
407 | //Yes, I know, this is insane ;) |
---|
408 | if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) continue; |
---|
409 | |
---|
410 | if(ui.options.snapMode != 'inner') { |
---|
411 | var ts = Math.abs(t - y2) <= 20; |
---|
412 | var bs = Math.abs(b - y1) <= 20; |
---|
413 | var ls = Math.abs(l - x2) <= 20; |
---|
414 | var rs = Math.abs(r - x1) <= 20; |
---|
415 | if(ts) ui.position.top = inst.convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top; |
---|
416 | if(bs) ui.position.top = inst.convertPositionTo("relative", { top: b, left: 0 }).top; |
---|
417 | if(ls) ui.position.left = inst.convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left; |
---|
418 | if(rs) ui.position.left = inst.convertPositionTo("relative", { top: 0, left: r }).left; |
---|
419 | } |
---|
420 | |
---|
421 | if(ui.options.snapMode != 'outer') { |
---|
422 | var ts = Math.abs(t - y1) <= 20; |
---|
423 | var bs = Math.abs(b - y2) <= 20; |
---|
424 | var ls = Math.abs(l - x1) <= 20; |
---|
425 | var rs = Math.abs(r - x2) <= 20; |
---|
426 | if(ts) ui.position.top = inst.convertPositionTo("relative", { top: t, left: 0 }).top; |
---|
427 | if(bs) ui.position.top = inst.convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top; |
---|
428 | if(ls) ui.position.left = inst.convertPositionTo("relative", { top: 0, left: l }).left; |
---|
429 | if(rs) ui.position.left = inst.convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left; |
---|
430 | } |
---|
431 | |
---|
432 | }; |
---|
433 | } |
---|
434 | }); |
---|
435 | |
---|
436 | $.ui.plugin.add("draggable", "connectToSortable", { |
---|
437 | start: function(e,ui) { |
---|
438 | |
---|
439 | var inst = $(this).data("draggable"); |
---|
440 | inst.sortables = []; |
---|
441 | $(ui.options.connectToSortable).each(function() { |
---|
442 | if($.data(this, 'sortable')) { |
---|
443 | var sortable = $.data(this, 'sortable'); |
---|
444 | inst.sortables.push({ |
---|
445 | instance: sortable, |
---|
446 | shouldRevert: sortable.options.revert |
---|
447 | }); |
---|
448 | sortable.refreshItems(); //Do a one-time refresh at start to refresh the containerCache |
---|
449 | sortable.propagate("activate", e, inst); |
---|
450 | } |
---|
451 | }); |
---|
452 | |
---|
453 | }, |
---|
454 | stop: function(e,ui) { |
---|
455 | |
---|
456 | //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper |
---|
457 | var inst = $(this).data("draggable"); |
---|
458 | |
---|
459 | $.each(inst.sortables, function() { |
---|
460 | if(this.instance.isOver) { |
---|
461 | this.instance.isOver = 0; |
---|
462 | inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance |
---|
463 | this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) |
---|
464 | if(this.shouldRevert) this.instance.options.revert = true; //revert here |
---|
465 | this.instance.mouseStop(e); |
---|
466 | |
---|
467 | //Also propagate receive event, since the sortable is actually receiving a element |
---|
468 | this.instance.element.triggerHandler("sortreceive", [e, $.extend(this.instance.ui(), { sender: inst.element })], this.instance.options["receive"]); |
---|
469 | |
---|
470 | this.instance.options.helper = this.instance.options._helper; |
---|
471 | } else { |
---|
472 | this.instance.propagate("deactivate", e, inst); |
---|
473 | } |
---|
474 | |
---|
475 | }); |
---|
476 | |
---|
477 | }, |
---|
478 | drag: function(e,ui) { |
---|
479 | |
---|
480 | var inst = $(this).data("draggable"), self = this; |
---|
481 | |
---|
482 | var checkPos = function(o) { |
---|
483 | |
---|
484 | var l = o.left, r = l + o.width, |
---|
485 | t = o.top, b = t + o.height; |
---|
486 | |
---|
487 | return (l < (this.positionAbs.left + this.offset.click.left) && (this.positionAbs.left + this.offset.click.left) < r |
---|
488 | && t < (this.positionAbs.top + this.offset.click.top) && (this.positionAbs.top + this.offset.click.top) < b); |
---|
489 | }; |
---|
490 | |
---|
491 | $.each(inst.sortables, function(i) { |
---|
492 | |
---|
493 | if(checkPos.call(inst, this.instance.containerCache)) { |
---|
494 | |
---|
495 | //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once |
---|
496 | if(!this.instance.isOver) { |
---|
497 | this.instance.isOver = 1; |
---|
498 | |
---|
499 | //Now we fake the start of dragging for the sortable instance, |
---|
500 | //by cloning the list group item, appending it to the sortable and using it as inst.currentItem |
---|
501 | //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) |
---|
502 | this.instance.currentItem = $(self).clone().appendTo(this.instance.element).data("sortable-item", true); |
---|
503 | this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it |
---|
504 | this.instance.options.helper = function() { return ui.helper[0]; }; |
---|
505 | |
---|
506 | e.target = this.instance.currentItem[0]; |
---|
507 | this.instance.mouseCapture(e, true); |
---|
508 | this.instance.mouseStart(e, true, true); |
---|
509 | |
---|
510 | //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes |
---|
511 | this.instance.offset.click.top = inst.offset.click.top; |
---|
512 | this.instance.offset.click.left = inst.offset.click.left; |
---|
513 | this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left; |
---|
514 | this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top; |
---|
515 | |
---|
516 | inst.propagate("toSortable", e); |
---|
517 | |
---|
518 | } |
---|
519 | |
---|
520 | //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 |
---|
521 | if(this.instance.currentItem) this.instance.mouseDrag(e); |
---|
522 | |
---|
523 | } else { |
---|
524 | |
---|
525 | //If it doesn't intersect with the sortable, and it intersected before, |
---|
526 | //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval |
---|
527 | if(this.instance.isOver) { |
---|
528 | this.instance.isOver = 0; |
---|
529 | this.instance.cancelHelperRemoval = true; |
---|
530 | this.instance.options.revert = false; //No revert here |
---|
531 | this.instance.mouseStop(e, true); |
---|
532 | this.instance.options.helper = this.instance.options._helper; |
---|
533 | |
---|
534 | //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size |
---|
535 | this.instance.currentItem.remove(); |
---|
536 | if(this.instance.placeholder) this.instance.placeholder.remove(); |
---|
537 | |
---|
538 | inst.propagate("fromSortable", e); |
---|
539 | } |
---|
540 | |
---|
541 | }; |
---|
542 | |
---|
543 | }); |
---|
544 | |
---|
545 | } |
---|
546 | }); |
---|
547 | |
---|
548 | $.ui.plugin.add("draggable", "stack", { |
---|
549 | start: function(e,ui) { |
---|
550 | var group = $.makeArray($(ui.options.stack.group)).sort(function(a,b) { |
---|
551 | return (parseInt($(a).css("zIndex"),10) || ui.options.stack.min) - (parseInt($(b).css("zIndex"),10) || ui.options.stack.min); |
---|
552 | }); |
---|
553 | |
---|
554 | $(group).each(function(i) { |
---|
555 | this.style.zIndex = ui.options.stack.min + i; |
---|
556 | }); |
---|
557 | |
---|
558 | this[0].style.zIndex = ui.options.stack.min + group.length; |
---|
559 | } |
---|
560 | }); |
---|
561 | |
---|
562 | })(jQuery); |
---|