/*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: $('
'), marker: $(''), 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("