first commit
This commit is contained in:
351
admin/static/js/jquery.tree-drag-drop.js
Normal file
351
admin/static/js/jquery.tree-drag-drop.js
Normal file
@@ -0,0 +1,351 @@
|
||||
/*global window, $, jQuery*/
|
||||
|
||||
if (typeof String.prototype.trim !== 'function') {
|
||||
String.prototype.trim = function () {
|
||||
"use strict";
|
||||
return this.replace(/^\s+|\s+$/g, '');
|
||||
};
|
||||
}
|
||||
|
||||
(function ($, undef) {
|
||||
"use strict";
|
||||
|
||||
$.treeDragDrop = {
|
||||
|
||||
defaults: {
|
||||
selectedClass: "tdd-selected",
|
||||
collapsedClass: "tdd-collapsed",
|
||||
expandedClass: "tdd-expanded",
|
||||
beforeClass: "tdd-before",
|
||||
afterClass: "tdd-after",
|
||||
cursorGrabbingUrl: null,
|
||||
inFolderThreshhold: 100,
|
||||
cursorAt: {left: 10, top: -40},
|
||||
dragContainer: $('<div class="tdd-dragContainer" />'),
|
||||
marker: $('<div />'),
|
||||
attributes: ["id", "class"],
|
||||
getUrl: null,
|
||||
updateUrl: null
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// helpers
|
||||
|
||||
function debug() {
|
||||
if (window.console && window.console.log) {
|
||||
//window.console.log(arguments);
|
||||
}
|
||||
}
|
||||
|
||||
function getContext(el) {
|
||||
return el.closest(".treeDragDrop");
|
||||
}
|
||||
|
||||
function getOptions(el) {
|
||||
return el.closest(".treeDragDrop").data("options");
|
||||
}
|
||||
|
||||
function serializeTree(el, ctx) {
|
||||
var data = [],
|
||||
intestingAttr = getOptions(el).attributes;
|
||||
|
||||
el.children("li").each(function (index, value) {
|
||||
var obj = {},
|
||||
attr = {};
|
||||
|
||||
obj.data = $(value).clone().children().remove().end().text().trim();
|
||||
$.each(intestingAttr, function (index, attribute) {
|
||||
if ($(value).attr(attribute) !== undef) {
|
||||
if (attribute === "class") {
|
||||
attr.classname = $(value).attr(attribute);
|
||||
} else {
|
||||
attr[attribute] = $(value).attr(attribute);
|
||||
}
|
||||
}
|
||||
});
|
||||
obj.attr = attr;
|
||||
if ($(value).children("ul").length > 0) {
|
||||
obj.children = serializeTree($(value).children("ul"));
|
||||
}
|
||||
data.push(obj);
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function sendTree(treeData, updateUrl) {
|
||||
var ajaxData;
|
||||
//treeData = serializeTree(tree);
|
||||
|
||||
debug(treeData);
|
||||
if (updateUrl !== null) {
|
||||
ajaxData = {tree: treeData};
|
||||
$.post(updateUrl, ajaxData, function (res) {
|
||||
//TODO: error handling
|
||||
return true;
|
||||
}).done(function (msg) {
|
||||
showInfoMessage('Uloženo','success');
|
||||
}).fail(function(xhr, status, error) {
|
||||
showInfoMessage('Chyba: ' + xhr.responseText,'danger');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// handlers
|
||||
|
||||
$.treeDragDrop.handlers = {
|
||||
|
||||
handleDraggableStart: function (e, o)
|
||||
{
|
||||
debug("handleDraggableStart");
|
||||
var options = getOptions($(e.target));
|
||||
$(e.target).addClass(options.selectedClass);
|
||||
document.onmousemove = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
$(e.target).data('position', $(e.target).index());
|
||||
|
||||
options.dropped = false;
|
||||
|
||||
//$("body").css("cursor", "url(" + options.cursorGrabbingUrl + ") , move").addClass("cursorGrabbing");
|
||||
},
|
||||
|
||||
handleDraggableDrag: function (e, o) {
|
||||
debug("handleDraggableDrag");
|
||||
},
|
||||
|
||||
handleDraggableStop: function (e, o) {
|
||||
debug("handleDraggableStop");
|
||||
|
||||
var ctx = getContext($(e.target)),
|
||||
options = getOptions($(e.target)),
|
||||
tree = $(".tdd-tree", ctx),
|
||||
target = $(e.target);
|
||||
// remove the mousemove Listener
|
||||
$("li, .tdd-tree", ctx).unbind("mousemove").removeClass(options.selectedClass);
|
||||
|
||||
var data = {
|
||||
id: target.data('id'),
|
||||
target: target.closest("ul").closest("li").data("id"),
|
||||
position: target.index(),
|
||||
after: target.prev().data('id'),
|
||||
before: target.next().data('id'),
|
||||
};
|
||||
|
||||
if ($(e.target).data('position') <= data.position)
|
||||
data.position++;
|
||||
|
||||
// build the array and post the ajax
|
||||
debug("handleDraggableStop: sendTree");
|
||||
sendTree(data, options.updateUrl);
|
||||
|
||||
//$("body").removeClass("cursorGrabbing").css("cursor", "auto");
|
||||
},
|
||||
|
||||
handleDroppableOut: function (e, o) {
|
||||
debug("handleDroppableOut", e.target);
|
||||
$(e.target).unbind("mousemove");
|
||||
},
|
||||
|
||||
handleDroppableOver: function (e, o) {
|
||||
debug("handleDroppableOver", e.target);
|
||||
var options = getOptions($(e.target)),
|
||||
selectedClass = options.selectedClass,
|
||||
beforeClass = options.beforeClass,
|
||||
afterClass = options.afterClass,
|
||||
marker = options.marker;
|
||||
|
||||
if ($(e.target).is("li")) {
|
||||
// bind MouseMove to the item to check if the draggable should be appended or placed before or after the item
|
||||
$(e.target).bind("mousemove", function (mme) {
|
||||
//debug("handleDroppableOver mousemove", mme.currentTarget);
|
||||
var target = $(mme.target).closest("li, ul"),
|
||||
x = mme.pageX - target.offset().left,
|
||||
y = mme.pageY - target.offset().top,
|
||||
threshhold = options.inFolderThreshhold;
|
||||
|
||||
// threshhold for apending or placing before/ater
|
||||
// will grow according to the deepness of nesting
|
||||
|
||||
if (target.find("ul").length !== 0) {
|
||||
threshhold = Math.min(options.inFolderThreshhold * (target.find("ul").length + 1), target.width() * 0.75);
|
||||
}
|
||||
|
||||
marker.removeClass(beforeClass, afterClass);
|
||||
|
||||
// prevent dropping items in itself
|
||||
if (target.hasClass(selectedClass) || target.parents("." + selectedClass).length !== 0) {
|
||||
marker.detach();
|
||||
} else if (target.parents(".tdd-trashbin").length !== 0) {
|
||||
target.parents(".tdd-trashbin").append(marker);
|
||||
} else {
|
||||
// append to item
|
||||
if (x > threshhold) {
|
||||
// append to ul if there is one
|
||||
if (target.is("li") && target.children("ul").length !== 0) {
|
||||
target.children("ul").append(marker);
|
||||
} else if (target.is("li")) {
|
||||
target.append(marker);
|
||||
}
|
||||
// place before item
|
||||
} else if (y < target.height() / 2) {
|
||||
marker.addClass(beforeClass);
|
||||
target.before(marker);
|
||||
// place after item
|
||||
} else {
|
||||
marker.addClass(afterClass);
|
||||
target.after(marker);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
// if tree is empty items may be put in the ul
|
||||
//} else if ($(e.target).hasClass("tdd-tree")/* && $(".tdd-tree").children().length === 0 */) {
|
||||
} else if ($(e.target).hasClass("tdd-tree")) {
|
||||
debug("tree");
|
||||
marker.removeClass(beforeClass, afterClass);
|
||||
marker.addClass(beforeClass);
|
||||
$(e.target).append(marker);
|
||||
} else if ($(e.target).hasClass("tdd-trashbin")) {
|
||||
debug("trashbin");
|
||||
$(e.target).append(marker);
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
handleDroppableDrop: function (e, o)
|
||||
{
|
||||
debug("handleDroppableDrop");
|
||||
|
||||
var draggable = $(o.draggable),
|
||||
dropable = $(e.target),
|
||||
marker = $.treeDragDrop.defaults.marker,
|
||||
ctx = draggable.data("tddCtx"),
|
||||
options = ctx.data("options");
|
||||
|
||||
// remove selection
|
||||
draggable.removeClass(options.selectedClass);
|
||||
|
||||
if (options.dropped)
|
||||
return true;
|
||||
|
||||
options.dropped = true;
|
||||
|
||||
// if its the trashbin put them all next to each other (no nesting)
|
||||
if (dropable.parents(".tdd-trashbin").length !== 0 || dropable.hasClass("tdd-trashbin")) {
|
||||
$(".tdd-trashbin").append(draggable);
|
||||
$("li", draggable).each(function (index, value) {
|
||||
$(".tdd-trashbin").append(value);
|
||||
});
|
||||
|
||||
// put the item directly in the tree ul if it contains no other element
|
||||
} else if (dropable.hasClass("tdd-tree") && $(".tdd-tree").children().length === 0) {
|
||||
$(".tdd-tree").append(draggable);
|
||||
// otherwise put it before the marker, which will be detached asap
|
||||
} else {
|
||||
marker.before(draggable);
|
||||
if (draggable.parent().is("li")) {
|
||||
draggable.wrap("<ul></ul>");
|
||||
}
|
||||
}
|
||||
marker.detach();
|
||||
//clean up empty uls if its not the tree or trashbin
|
||||
$("ul", ctx).not(".tdd-trashbin, .tdd-tree").each(function () {
|
||||
if ($(this).children().length === 0) {
|
||||
debug($(this));
|
||||
$(this).remove();
|
||||
}
|
||||
});
|
||||
// adjust expand/collapse icons
|
||||
$("li", ctx).has("ul").not("li." + options.collapsedClass).addClass(options.expandedClass);
|
||||
$("li", ctx).not("li:has(ul)").removeClass(options.expandedClass).removeClass(options.collapsedClass);
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
|
||||
// toggle expand/collapse
|
||||
handleClick: function (e) {
|
||||
|
||||
var target = $(e.target),
|
||||
ctx = getContext($(e.target)),
|
||||
tree = $(".tdd-tree", ctx),
|
||||
options = getOptions($(e.target)),
|
||||
collapsed = options.collapsedClass,
|
||||
expanded = options.expandedClass;
|
||||
|
||||
|
||||
if (target.children("ul").length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
if (target.hasClass(collapsed)) {
|
||||
target.removeClass(collapsed).addClass(expanded);
|
||||
target.children("ul").show();
|
||||
} else {
|
||||
target.removeClass(expanded).addClass(collapsed);
|
||||
target.children("ul").hide();
|
||||
}
|
||||
}
|
||||
|
||||
debug("handleClick: sendTree");
|
||||
sendTree(tree, options.updateUrl);
|
||||
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// the Prototype
|
||||
|
||||
$.fn.treeDragDrop = function (options) {
|
||||
|
||||
//extend the global default with the options for the element
|
||||
options = $.extend({}, $.treeDragDrop.defaults, options);
|
||||
|
||||
|
||||
|
||||
return this.each(function () {
|
||||
var ctx = $(this),
|
||||
data = ctx.data('treeDragDrop');
|
||||
|
||||
// init the element
|
||||
if (!data) {
|
||||
$("li", ctx).draggable({
|
||||
addClasses: false,
|
||||
cursorAt: $.treeDragDrop.defaults.cursorAt,
|
||||
helper: "clone",
|
||||
appendTo: "body",
|
||||
opacity: 0.2,
|
||||
delay: 10,
|
||||
handle: ".drag-drop-mover",
|
||||
//create: $.treeDragDrop.handlers.handleDraggableCreate,
|
||||
start: $.treeDragDrop.handlers.handleDraggableStart,
|
||||
//drag: $.treeDragDrop.handlers.handleDraggableDrag,
|
||||
stop: $.treeDragDrop.handlers.handleDraggableStop
|
||||
});
|
||||
$("li, ul", ctx).droppable({
|
||||
addClasses: false,
|
||||
greedy: true,
|
||||
tolerance: "pointer",
|
||||
drop: $.treeDragDrop.handlers.handleDroppableDrop,
|
||||
over: $.treeDragDrop.handlers.handleDroppableOver,
|
||||
out: $.treeDragDrop.handlers.handleDroppableOut
|
||||
|
||||
}).data("tddCtx", ctx);
|
||||
|
||||
$.treeDragDrop.defaults.marker.bind("mousemove", function () { return false; });
|
||||
$.treeDragDrop.defaults.marker.bind("mouseover", function () { return false; });
|
||||
|
||||
ctx.data('options', options);
|
||||
ctx.data('treeDragDrop', {inited: true});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
}(jQuery));
|
||||
|
||||
Reference in New Issue
Block a user