352 lines
9.8 KiB
JavaScript
352 lines
9.8 KiB
JavaScript
/*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));
|
|
|