mirror of
https://github.com/samsonjs/stormy-weather.git
synced 2026-03-25 09:15:57 +00:00
297 lines
11 KiB
JavaScript
297 lines
11 KiB
JavaScript
// jQuery List DragSort v0.4
|
|
// Website: http://dragsort.codeplex.com/
|
|
// License: http://dragsort.codeplex.com/license
|
|
|
|
(function($) {
|
|
|
|
$.fn.dragsort = function(options) {
|
|
var opts = $.extend({}, $.fn.dragsort.defaults, options);
|
|
var lists = [];
|
|
var list = null, lastPos = null;
|
|
|
|
this.each(function(i, cont) {
|
|
|
|
if ($(cont).is("table") && $(cont).children().size() == 1 && $(cont).children().is("tbody"))
|
|
cont = $(cont).children().get(0);
|
|
|
|
var newList = {
|
|
draggedItem: null,
|
|
placeHolderItem: null,
|
|
pos: null,
|
|
offset: null,
|
|
offsetLimit: null,
|
|
scroll: null,
|
|
container: cont,
|
|
|
|
init: function() {
|
|
$(this.container).attr("data-listIdx", i).mousedown(this.grabItem)
|
|
$(this.container).children(opts.itemSelector).each(function(j) { $(this).attr("data-itemIdx", j); });
|
|
},
|
|
|
|
grabItem: function(e) {
|
|
if (e.which != 1 || $(e.target).is(opts.dragSelectorExclude))
|
|
return;
|
|
|
|
var elm = e.target;
|
|
while (!$(elm).is("[data-listIdx='" + $(this).attr("data-listIdx") + "'] " + opts.dragSelector)) {
|
|
if (elm == this) return;
|
|
elm = elm.parentNode;
|
|
}
|
|
|
|
if (list != null && list.draggedItem != null)
|
|
list.dropItem();
|
|
|
|
list = lists[$(this).attr("data-listIdx")];
|
|
list.draggedItem = $(elm).closest(opts.itemSelector);
|
|
var mt = parseInt(list.draggedItem.css("marginTop"));
|
|
var ml = parseInt(list.draggedItem.css("marginLeft"));
|
|
list.offset = list.draggedItem.offset();
|
|
list.offset.top = e.pageY - list.offset.top + (isNaN(mt) ? 0 : mt) - 1;
|
|
list.offset.left = e.pageX - list.offset.left + (isNaN(ml) ? 0 : ml) - 1;
|
|
list.draggedItem.startOffset = list.draggedItem.offset()
|
|
list.draggedItem.startTime = +new Date()
|
|
|
|
if (!opts.dragBetween) {
|
|
var containerHeight = $(list.container).outerHeight() == 0 ? Math.max(1, Math.round(0.5 + $(list.container).children(opts.itemSelector).size() * list.draggedItem.outerWidth() / $(list.container).outerWidth())) * list.draggedItem.outerHeight() : $(list.container).outerHeight();
|
|
list.offsetLimit = $(list.container).offset();
|
|
list.offsetLimit.right = list.offsetLimit.left + $(list.container).outerWidth() - list.draggedItem.outerWidth();
|
|
list.offsetLimit.bottom = list.offsetLimit.top + containerHeight - list.draggedItem.outerHeight();
|
|
}
|
|
|
|
var h = list.draggedItem.height();
|
|
var w = list.draggedItem.width();
|
|
var orig = list.draggedItem.attr("style");
|
|
list.draggedItem.attr("data-origStyle", orig ? orig : "");
|
|
if (opts.itemSelector == "tr") {
|
|
list.draggedItem.children().each(function() { $(this).width($(this).width()); });
|
|
list.placeHolderItem = list.draggedItem.clone().attr("data-placeHolder", true);
|
|
list.draggedItem.after(list.placeHolderItem);
|
|
list.placeHolderItem.children().each(function() { $(this).css({ borderWidth:0, width: $(this).width() + 1, height: $(this).height() + 1 }).html(" "); });
|
|
} else {
|
|
list.draggedItem.after(opts.placeHolderTemplate);
|
|
list.placeHolderItem = list.draggedItem.next().css({ height: h, width: w }).attr("data-placeHolder", true);
|
|
}
|
|
list.draggedItem.css({ position: "absolute", opacity: 0.8, "z-index": 999, height: h, width: w });
|
|
|
|
$(lists).each(function(i, l) { l.createDropTargets(); l.buildPositionTable(); });
|
|
|
|
list.scroll = { moveX: 0, moveY: 0, maxX: $(document).width() - $(window).width(), maxY: $(document).height() - $(window).height() };
|
|
list.scroll.scrollY = window.setInterval(function() {
|
|
if (opts.scrollContainer != window) {
|
|
$(opts.scrollContainer).scrollTop($(opts.scrollContainer).scrollTop() + list.scroll.moveY);
|
|
return;
|
|
}
|
|
var t = $(opts.scrollContainer).scrollTop();
|
|
if (list.scroll.moveY > 0 && t < list.scroll.maxY || list.scroll.moveY < 0 && t > 0) {
|
|
$(opts.scrollContainer).scrollTop(t + list.scroll.moveY);
|
|
list.draggedItem.css("top", list.draggedItem.offset().top + list.scroll.moveY + 1);
|
|
}
|
|
}, 10);
|
|
list.scroll.scrollX = window.setInterval(function() {
|
|
if (opts.scrollContainer != window) {
|
|
$(opts.scrollContainer).scrollLeft($(opts.scrollContainer).scrollLeft() + list.scroll.moveX);
|
|
return;
|
|
}
|
|
var l = $(opts.scrollContainer).scrollLeft();
|
|
if (list.scroll.moveX > 0 && l < list.scroll.maxX || list.scroll.moveX < 0 && l > 0) {
|
|
$(opts.scrollContainer).scrollLeft(l + list.scroll.moveX);
|
|
list.draggedItem.css("left", list.draggedItem.offset().left + list.scroll.moveX + 1);
|
|
}
|
|
}, 10);
|
|
|
|
list.setPos(e.pageX, e.pageY);
|
|
$(document).bind("selectstart", list.stopBubble); //stop ie text selection
|
|
$(document).bind("mousemove", list.swapItems);
|
|
$(document).bind("mouseup", list.dropItem);
|
|
if (opts.scrollContainer != window)
|
|
$(window).bind("DOMMouseScroll mousewheel", list.wheel);
|
|
return false; //stop moz text selection
|
|
},
|
|
|
|
setPos: function(x, y) {
|
|
var top = y - this.offset.top;
|
|
var left = x - this.offset.left;
|
|
|
|
if (!opts.dragBetween) {
|
|
top = Math.min(this.offsetLimit.bottom, Math.max(top, this.offsetLimit.top));
|
|
left = Math.min(this.offsetLimit.right, Math.max(left, this.offsetLimit.left));
|
|
}
|
|
|
|
this.draggedItem.parents().each(function() {
|
|
if ($(this).css("position") != "static" && (!$.browser.mozilla || $(this).css("display") != "table")) {
|
|
var offset = $(this).offset();
|
|
top -= offset.top;
|
|
left -= offset.left;
|
|
return false;
|
|
}
|
|
});
|
|
|
|
if (opts.scrollContainer == window) {
|
|
y -= $(window).scrollTop();
|
|
x -= $(window).scrollLeft();
|
|
y = Math.max(0, y - $(window).height() + 5) + Math.min(0, y - 5);
|
|
x = Math.max(0, x - $(window).width() + 5) + Math.min(0, x - 5);
|
|
} else {
|
|
var cont = $(opts.scrollContainer);
|
|
var offset = cont.offset();
|
|
y = Math.max(0, y - cont.height() - offset.top) + Math.min(0, y - offset.top);
|
|
x = Math.max(0, x - cont.width() - offset.left) + Math.min(0, x - offset.left);
|
|
}
|
|
|
|
list.scroll.moveX = x == 0 ? 0 : x * opts.scrollSpeed / Math.abs(x);
|
|
list.scroll.moveY = y == 0 ? 0 : y * opts.scrollSpeed / Math.abs(y);
|
|
|
|
this.draggedItem.css({ top: top, left: left });
|
|
},
|
|
|
|
wheel: function(e) {
|
|
if (($.browser.safari || $.browser.mozilla) && list && opts.scrollContainer != window) {
|
|
var cont = $(opts.scrollContainer);
|
|
var offset = cont.offset();
|
|
if (e.pageX > offset.left && e.pageX < offset.left + cont.width() && e.pageY > offset.top && e.pageY < offset.top + cont.height()) {
|
|
var delta = e.detail ? e.detail * 5 : e.wheelDelta / -2;
|
|
cont.scrollTop(cont.scrollTop() + delta);
|
|
e.preventDefault();
|
|
}
|
|
}
|
|
},
|
|
|
|
buildPositionTable: function() {
|
|
var item = this.draggedItem == null ? null : this.draggedItem.get(0);
|
|
var pos = [];
|
|
$(this.container).children(opts.itemSelector).each(function(i, elm) {
|
|
if (elm != item) {
|
|
var loc = $(elm).offset();
|
|
loc.right = loc.left + $(elm).width();
|
|
loc.bottom = loc.top + $(elm).height();
|
|
loc.elm = elm;
|
|
pos.push(loc);
|
|
}
|
|
});
|
|
this.pos = pos;
|
|
},
|
|
|
|
dropItem: function() {
|
|
if (list.draggedItem == null)
|
|
return;
|
|
|
|
list.placeHolderItem.before(list.draggedItem);
|
|
|
|
//list.draggedItem.attr("style", "") doesn't work on IE8 and jQuery 1.5 or lower
|
|
//list.draggedItem.removeAttr("style") doesn't work on chrome and jQuery 1.6 (works jQuery 1.5 or lower)
|
|
var orig = list.draggedItem.attr("data-origStyle");
|
|
list.draggedItem.attr("style", orig);
|
|
if (orig == "")
|
|
list.draggedItem.removeAttr("style");
|
|
list.draggedItem.removeAttr("data-origStyle");
|
|
list.placeHolderItem.remove();
|
|
|
|
$("[data-dropTarget]").remove();
|
|
|
|
window.clearInterval(list.scroll.scrollY);
|
|
window.clearInterval(list.scroll.scrollX);
|
|
|
|
var changed = false;
|
|
$(lists).each(function() {
|
|
$(this.container).children(opts.itemSelector).each(function(j) {
|
|
if (parseInt($(this).attr("data-itemIdx")) != j) {
|
|
changed = true;
|
|
$(this).attr("data-itemIdx", j);
|
|
}
|
|
});
|
|
});
|
|
|
|
var duration = +new Date() - list.draggedItem.startTime
|
|
, offset = list.draggedItem.offset()
|
|
, diffY = Math.abs(list.draggedItem.startOffset.top - offset.top)
|
|
, diffX = Math.abs(list.draggedItem.startOffset.left - offset.left)
|
|
, itemClicked = duration < 500 && diffX < 3 && diffY < 3
|
|
|
|
if (changed)
|
|
opts.dragEnd.apply(list.draggedItem);
|
|
else if (itemClicked)
|
|
opts.itemClicked(list.draggedItem)
|
|
|
|
list.draggedItem = null;
|
|
$(document).unbind("selectstart", list.stopBubble);
|
|
$(document).unbind("mousemove", list.swapItems);
|
|
$(document).unbind("mouseup", list.dropItem);
|
|
if (opts.scrollContainer != window)
|
|
$(window).unbind("DOMMouseScroll mousewheel", list.wheel);
|
|
return false;
|
|
},
|
|
|
|
stopBubble: function() { return false; },
|
|
|
|
swapItems: function(e) {
|
|
if (list.draggedItem == null)
|
|
return false;
|
|
|
|
list.setPos(e.pageX, e.pageY);
|
|
|
|
var ei = list.findPos(e.pageX, e.pageY);
|
|
var nlist = list;
|
|
for (var i = 0; ei == -1 && opts.dragBetween && i < lists.length; i++) {
|
|
ei = lists[i].findPos(e.pageX, e.pageY);
|
|
nlist = lists[i];
|
|
}
|
|
|
|
if (ei == -1 || $(nlist.pos[ei].elm).attr("data-placeHolder"))
|
|
return false;
|
|
|
|
if (lastPos == null || lastPos.top > list.draggedItem.offset().top || lastPos.left > list.draggedItem.offset().left)
|
|
$(nlist.pos[ei].elm).before(list.placeHolderItem);
|
|
else
|
|
$(nlist.pos[ei].elm).after(list.placeHolderItem);
|
|
|
|
$(lists).each(function(i, l) { l.createDropTargets(); l.buildPositionTable(); });
|
|
lastPos = list.draggedItem.offset();
|
|
return false;
|
|
},
|
|
|
|
findPos: function(x, y) {
|
|
for (var i = 0; i < this.pos.length; i++) {
|
|
if (this.pos[i].left < x && this.pos[i].right > x && this.pos[i].top < y && this.pos[i].bottom > y)
|
|
return i;
|
|
}
|
|
return -1;
|
|
},
|
|
|
|
createDropTargets: function() {
|
|
if (!opts.dragBetween)
|
|
return;
|
|
|
|
$(lists).each(function() {
|
|
var ph = $(this.container).find("[data-placeHolder]");
|
|
var dt = $(this.container).find("[data-dropTarget]");
|
|
if (ph.size() > 0 && dt.size() > 0)
|
|
dt.remove();
|
|
else if (ph.size() == 0 && dt.size() == 0) {
|
|
//list.placeHolderItem.clone().removeAttr("data-placeHolder") crashes in IE7 and jquery 1.5.1 (doesn't in jquery 1.4.2 or IE8)
|
|
$(this.container).append(list.placeHolderItem.removeAttr("data-placeHolder").clone().attr("data-dropTarget", true));
|
|
list.placeHolderItem.attr("data-placeHolder", true);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
newList.init();
|
|
lists.push(newList);
|
|
});
|
|
|
|
return this;
|
|
};
|
|
|
|
$.fn.dragsort.defaults = {
|
|
itemClicked: function() { },
|
|
itemSelector: "li",
|
|
dragSelector: "li",
|
|
dragSelectorExclude: "input, textarea, a[href]",
|
|
dragEnd: function() { },
|
|
dragBetween: false,
|
|
placeHolderTemplate: "<li> </li>",
|
|
scrollContainer: window,
|
|
scrollSpeed: 5
|
|
};
|
|
|
|
})(jQuery);
|