国内流行的内容管理系统(CMS)多端全媒体解决方案 https://www.dedebiz.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

563 lines
24KB

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