feat: Add comprehensive documentation suite and reorganize project structure

- Created complete documentation in docs/ directory
- Added PROJECT_OVERVIEW.md with feature highlights and getting started guide
- Added ARCHITECTURE.md with system design and technical details
- Added SECURITY.md with comprehensive security implementation guide
- Added DEVELOPMENT.md with development workflows and best practices
- Added DEPLOYMENT.md with production deployment instructions
- Added API.md with complete REST API documentation
- Added CONTRIBUTING.md with contribution guidelines
- Added CHANGELOG.md with version history and migration notes
- Reorganized all documentation files into docs/ directory for better organization
- Updated README.md with proper documentation links and quick navigation
- Enhanced project structure with professional documentation standards
This commit is contained in:
SamiAhmed7777
2025-10-21 00:39:45 -07:00
commit 0b7e2d0a5b
6080 changed files with 1332936 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 649 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1010 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 545 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1010 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1010 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 B

View File

@@ -0,0 +1,113 @@
/*
* Async Treeview 0.1 - Lazy-loading extension for Treeview
*
* http://bassistance.de/jquery-plugins/jquery-plugin-treeview/
*
* Copyright (c) 2007 Jörn Zaefferer
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Revision: $Id$
*
*/
;(function($) {
function load(settings, root, child, container) {
function createNode(parent) {
var current = $("<li/>").attr("id", this.id || "").html("<span>" + this.text + "</span>").appendTo(parent);
if (this.classes) {
current.children("span").addClass(this.classes);
}
if (this.expanded) {
current.addClass("open");
}
if (this.hasChildren || this.children && this.children.length) {
var branch = $("<ul/>").appendTo(current);
if (this.hasChildren) {
current.addClass("hasChildren");
createNode.call({
classes: "placeholder",
text: "&nbsp;",
children:[]
}, branch);
}
if (this.children && this.children.length) {
$.each(this.children, createNode, [branch])
}
}
}
$.ajax($.extend(true, {
url: settings.url,
dataType: "json",
data: {
root: root
},
success: function(response) {
child.empty();
$.each(response, createNode, [child]);
$(container).treeview({add: child});
}
}, settings.ajax));
/*
$.getJSON(settings.url, {root: root}, function(response) {
function createNode(parent) {
var current = $("<li/>").attr("id", this.id || "").html("<span>" + this.text + "</span>").appendTo(parent);
if (this.classes) {
current.children("span").addClass(this.classes);
}
if (this.expanded) {
current.addClass("open");
}
if (this.hasChildren || this.children && this.children.length) {
var branch = $("<ul/>").appendTo(current);
if (this.hasChildren) {
current.addClass("hasChildren");
createNode.call({
classes: "placeholder",
text: "&nbsp;",
children:[]
}, branch);
}
if (this.children && this.children.length) {
$.each(this.children, createNode, [branch])
}
}
}
child.empty();
$.each(response, createNode, [child]);
$(container).treeview({add: child});
});
*/
}
var proxied = $.fn.treeview;
$.fn.treeview = function(settings) {
if (!settings.url) {
return proxied.apply(this, arguments);
}
if (!settings.root) {
settings.root = "source";
}
var container = this;
if (!container.children().size())
load(settings, settings.root, this, container);
var userToggle = settings.toggle;
return proxied.call(this, $.extend({}, settings, {
collapsed: true,
toggle: function() {
var $this = $(this);
if ($this.hasClass("hasChildren")) {
var childList = $this.removeClass("hasChildren").find("ul");
load(settings, this.id, childList, container);
}
if (userToggle) {
userToggle.apply(this, arguments);
}
}
}));
};
})(jQuery);

View File

@@ -0,0 +1,75 @@
.treeview, .treeview ul {
padding: 0;
margin: 0;
list-style: none;
}
.treeview ul {
background-color: white;
margin-top: 4px;
}
.treeview .hitarea {
background: url(images/treeview-default.gif) -64px -25px no-repeat;
height: 16px;
width: 16px;
margin-left: -16px;
float: left;
/* cursor: pointer;
*/
}
/* fix for IE6 */
* html .hitarea {
display: inline;
float:none;
}
.treeview li {
margin: 0;
padding: 3px 0pt 3px 16px;
font-size: 13px;
}
.treeview a.selected {
background-color: #eee;
}
#treecontrol { margin: 1em 0; display: none; }
.treeview .hover { color: red; cursor: pointer; }
.treeview li { background: url(images/treeview-default-line.gif) 0 0 no-repeat; }
.treeview li.collapsable, .treeview li.expandable { background-position: 0 -176px; }
.treeview .expandable-hitarea { background-position: -80px -3px; }
.treeview li.last { background-position: 0 -1766px }
.treeview li.lastCollapsable, .treeview li.lastExpandable { background-image: url(images/treeview-default.gif); }
.treeview li.lastCollapsable { background-position: 0 -111px }
.treeview li.lastExpandable { background-position: -32px -67px }
.treeview div.lastCollapsable-hitarea, .treeview div.lastExpandable-hitarea { background-position: 0; }
.treeview-red li { background-image: url(images/treeview-red-line.gif); }
.treeview-red .hitarea, .treeview-red li.lastCollapsable, .treeview-red li.lastExpandable { background-image: url(images/treeview-red.gif); }
.treeview-black li { background-image: url(images/treeview-black-line.gif); }
.treeview-black .hitarea, .treeview-black li.lastCollapsable, .treeview-black li.lastExpandable { background-image: url(images/treeview-black.gif); }
.treeview-gray li { background-image: url(images/treeview-gray-line.gif); }
.treeview-gray .hitarea, .treeview-gray li.lastCollapsable, .treeview-gray li.lastExpandable { background-image: url(images/treeview-gray.gif); }
.treeview-famfamfam li { background-image: url(images/treeview-famfamfam-line.gif); }
.treeview-famfamfam .hitarea, .treeview-famfamfam li.lastCollapsable, .treeview-famfamfam li.lastExpandable { background-image: url(images/treeview-famfamfam.gif); }
.treeview .placeholder {
background: url(images/ajax-loader.gif) 0 0 no-repeat;
height: 16px;
width: 16px;
display: block;
}
.filetree li { padding: 3px 0 2px 16px; }
.filetree span.folder, .filetree span.file { padding: 1px 0 1px 16px; display: block; }
.filetree span.folder { background: url(images/folder.gif) 0 0 no-repeat; }
.filetree li.expandable span.folder { background: url(images/folder-closed.gif) 0 0 no-repeat; }

View File

@@ -0,0 +1,37 @@
(function($) {
var CLASSES = $.treeview.classes;
var proxied = $.fn.treeview;
$.fn.treeview = function(settings) {
settings = $.extend({}, settings);
if (settings.add) {
return this.trigger("add", [settings.add]);
}
if (settings.remove) {
return this.trigger("remove", [settings.remove]);
}
return proxied.apply(this, arguments).bind("add", function(event, branches) {
$(branches).prev()
.removeClass(CLASSES.last)
.removeClass(CLASSES.lastCollapsable)
.removeClass(CLASSES.lastExpandable)
.find(">.hitarea")
.removeClass(CLASSES.lastCollapsableHitarea)
.removeClass(CLASSES.lastExpandableHitarea);
$(branches).find("li").andSelf().prepareBranches(settings).applyClasses(settings, $(this).data("toggler"));
}).bind("remove", function(event, branches) {
var prev = $(branches).prev();
var parent = $(branches).parent();
$(branches).remove();
prev.filter(":last-child").addClass(CLASSES.last)
.filter("." + CLASSES.expandable).replaceClass(CLASSES.last, CLASSES.lastExpandable).end()
.find(">.hitarea").replaceClass(CLASSES.expandableHitarea, CLASSES.lastExpandableHitarea).end()
.filter("." + CLASSES.collapsable).replaceClass(CLASSES.last, CLASSES.lastCollapsable).end()
.find(">.hitarea").replaceClass(CLASSES.collapsableHitarea, CLASSES.lastCollapsableHitarea);
if (parent.is(":not(:has(>))") && parent[0] != this) {
parent.parent().removeClass(CLASSES.collapsable).removeClass(CLASSES.expandable)
parent.siblings(".hitarea").andSelf().remove();
}
});
};
})(jQuery);

View File

@@ -0,0 +1,256 @@
/*
* Treeview 1.5pre - jQuery plugin to hide and show branches of a tree
*
* http://bassistance.de/jquery-plugins/jquery-plugin-treeview/
* http://docs.jquery.com/Plugins/Treeview
*
* Copyright (c) 2007 Jörn Zaefferer
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Revision: $Id: jquery.treeview.js 5759 2008-07-01 07:50:28Z joern.zaefferer $
*
*/
;(function($) {
// TODO rewrite as a widget, removing all the extra plugins
$.extend($.fn, {
swapClass: function(c1, c2) {
var c1Elements = this.filter('.' + c1);
this.filter('.' + c2).removeClass(c2).addClass(c1);
c1Elements.removeClass(c1).addClass(c2);
return this;
},
replaceClass: function(c1, c2) {
return this.filter('.' + c1).removeClass(c1).addClass(c2).end();
},
hoverClass: function(className) {
className = className || "hover";
return this.hover(function() {
$(this).addClass(className);
}, function() {
$(this).removeClass(className);
});
},
heightToggle: function(animated, callback) {
animated ?
this.animate({ height: "toggle" }, animated, callback) :
this.each(function(){
jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
if(callback)
callback.apply(this, arguments);
});
},
heightHide: function(animated, callback) {
if (animated) {
this.animate({ height: "hide" }, animated, callback);
} else {
this.hide();
if (callback)
this.each(callback);
}
},
prepareBranches: function(settings) {
if (!settings.prerendered) {
// mark last tree items
this.filter(":last-child:not(ul)").addClass(CLASSES.last);
// collapse whole tree, or only those marked as closed, anyway except those marked as open
this.filter((settings.collapsed ? "" : "." + CLASSES.closed) + ":not(." + CLASSES.open + ")").find(">ul").hide();
}
// return all items with sublists
return this.filter(":has(>ul)");
},
applyClasses: function(settings, toggler) {
// TODO use event delegation
this.filter(":has(>ul):not(:has(>a))").find(">span").unbind("click.treeview").bind("click.treeview", function(event) {
// don't handle click events on children, eg. checkboxes
if ( this == event.target )
toggler.apply($(this).next());
}).add( $("a", this) ).hoverClass();
if (!settings.prerendered) {
// handle closed ones first
this.filter(":has(>ul:hidden)")
.addClass(CLASSES.expandable)
.replaceClass(CLASSES.last, CLASSES.lastExpandable);
// handle open ones
this.not(":has(>ul:hidden)")
.addClass(CLASSES.collapsable)
.replaceClass(CLASSES.last, CLASSES.lastCollapsable);
// create hitarea if not present
var hitarea = this.find("div." + CLASSES.hitarea);
if (!hitarea.length)
hitarea = this.prepend("<div class=\"" + CLASSES.hitarea + "\"/>").find("div." + CLASSES.hitarea);
hitarea.removeClass().addClass(CLASSES.hitarea).each(function() {
var classes = "";
$.each($(this).parent().attr("class").split(" "), function() {
classes += this + "-hitarea ";
});
$(this).addClass( classes );
})
}
// apply event to hitarea
this.find("div." + CLASSES.hitarea).click( toggler );
},
treeview: function(settings) {
settings = $.extend({
cookieId: "treeview"
}, settings);
if ( settings.toggle ) {
var callback = settings.toggle;
settings.toggle = function() {
return callback.apply($(this).parent()[0], arguments);
};
}
// factory for treecontroller
function treeController(tree, control) {
// factory for click handlers
function handler(filter) {
return function() {
// reuse toggle event handler, applying the elements to toggle
// start searching for all hitareas
toggler.apply( $("div." + CLASSES.hitarea, tree).filter(function() {
// for plain toggle, no filter is provided, otherwise we need to check the parent element
return filter ? $(this).parent("." + filter).length : true;
}) );
return false;
};
}
// click on first element to collapse tree
$("a:eq(0)", control).click( handler(CLASSES.collapsable) );
// click on second to expand tree
$("a:eq(1)", control).click( handler(CLASSES.expandable) );
// click on third to toggle tree
$("a:eq(2)", control).click( handler() );
}
// handle toggle event
function toggler() {
$(this)
.parent()
// swap classes for hitarea
.find(">.hitarea")
.swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
.swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
.end()
// swap classes for parent li
.swapClass( CLASSES.collapsable, CLASSES.expandable )
.swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
// find child lists
.find( ">ul" )
// toggle them
.heightToggle( settings.animated, settings.toggle );
if ( settings.unique ) {
$(this).parent()
.siblings()
// swap classes for hitarea
.find(">.hitarea")
.replaceClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
.replaceClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
.end()
.replaceClass( CLASSES.collapsable, CLASSES.expandable )
.replaceClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
.find( ">ul" )
.heightHide( settings.animated, settings.toggle );
}
}
this.data("toggler", toggler);
function serialize() {
function binary(arg) {
return arg ? 1 : 0;
}
var data = [];
branches.each(function(i, e) {
data[i] = $(e).is(":has(>ul:visible)") ? 1 : 0;
});
$.cookie(settings.cookieId, data.join(""), settings.cookieOptions );
}
function deserialize() {
var stored = $.cookie(settings.cookieId);
if ( stored ) {
var data = stored.split("");
branches.each(function(i, e) {
$(e).find(">ul")[ parseInt(data[i]) ? "show" : "hide" ]();
});
}
}
// add treeview class to activate styles
this.addClass("treeview");
// prepare branches and find all tree items with child lists
var branches = this.find("li").prepareBranches(settings);
switch(settings.persist) {
case "cookie":
var toggleCallback = settings.toggle;
settings.toggle = function() {
serialize();
if (toggleCallback) {
toggleCallback.apply(this, arguments);
}
};
deserialize();
break;
case "location":
var current = this.find("a").filter(function() {
return this.href.toLowerCase() == location.href.toLowerCase();
});
if ( current.length ) {
// TODO update the open/closed classes
var items = current.addClass("selected").parents("ul, li").add( current.next() ).show();
if (settings.prerendered) {
// if prerendered is on, replicate the basic class swapping
items.filter("li")
.swapClass( CLASSES.collapsable, CLASSES.expandable )
.swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
.find(">.hitarea")
.swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
.swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea );
}
}
break;
}
branches.applyClasses(settings, toggler);
// if control option is set, create the treecontroller and show it
if ( settings.control ) {
treeController(this, settings.control);
$(settings.control).show();
}
return this;
}
});
// classes used by the plugin
// need to be styled via external stylesheet, see first example
$.treeview = {};
var CLASSES = ($.treeview.classes = {
open: "open",
closed: "closed",
expandable: "expandable",
expandableHitarea: "expandable-hitarea",
lastExpandableHitarea: "lastExpandable-hitarea",
collapsable: "collapsable",
collapsableHitarea: "collapsable-hitarea",
lastCollapsableHitarea: "lastCollapsable-hitarea",
lastCollapsable: "lastCollapsable",
lastExpandable: "lastExpandable",
last: "last",
hitarea: "hitarea"
});
})(jQuery);

View File

@@ -0,0 +1,378 @@
/*
* jQuery UI Sortable
*
* Copyright (c) 2008 Paul Bakaus
* Dual licensed under the MIT (MIT-LICENSE.txt)
* and GPL (GPL-LICENSE.txt) licenses.
*
* http://docs.jquery.com/UI/Sortables
*
* Depends:
* ui.base.js
*
* Revision: $Id: ui.sortable.js 5262 2008-04-17 13:13:51Z paul.bakaus $
*/
;(function($) {
if (window.Node && Node.prototype && !Node.prototype.contains) {
Node.prototype.contains = function (arg) {
return !!(this.compareDocumentPosition(arg) & 16);
};
}
$.widget("ui.sortableTree", $.extend($.ui.mouse, {
init: function() {
//Initialize needed constants
var self = this, o = this.options;
this.containerCache = {};
this.element.addClass("ui-sortableTree");
//Get the items
this.refresh();
//Let's determine the parent's offset
if(!(/(relative|absolute|fixed)/).test(this.element.css('position'))) this.element.css('position', 'relative');
this.offset = this.element.offset();
//Initialize mouse events for interaction
this.mouseInit();
//Prepare cursorAt
if(o.cursorAt && o.cursorAt.constructor == Array)
o.cursorAt = { left: o.cursorAt[0], top: o.cursorAt[1] };
},
plugins: {},
ui: function(inst) {
return {
helper: (inst || this)["helper"],
position: (inst || this)["position"].current,
absolutePosition: (inst || this)["position"].absolute,
instance: this,
options: this.options,
element: this.element,
item: (inst || this)["currentItem"],
sender: inst ? inst.element : null
};
},
propagate: function(n,e,inst) {
$.ui.plugin.call(this, n, [e, this.ui(inst)]);
this.element.triggerHandler(n == "sort" ? n : "sort"+n, [e, this.ui(inst)], this.options[n]);
},
serialize: function(o) {
var items = $(this.options.items, this.element).not('.ui-sortableTree-helper'); //Only the items of the sortable itself
var str = []; o = o || {};
items.each(function() {
var res = ($(this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
if(res) str.push((o.key || res[1])+'[]='+(o.key ? res[1] : res[2]));
});
return str.join('&');
},
toArray: function(attr) {
var items = $(this.options.items, this.element).not('.ui-sortableTree-helper'); //Only the items of the sortable itself
var ret = [];
items.each(function() { ret.push($(this).attr(attr || 'id')); });
return ret;
},
enable: function() {
this.element.removeClass("ui-sortableTree-disabled");
this.options.disabled = false;
},
disable: function() {
this.element.addClass("ui-sortableTree-disabled");
this.options.disabled = true;
},
/* Be careful with the following core functions */
intersectsWith: function(item) {
var x1 = this.position.absolute.left - 10, x2 = x1 + 10,
y1 = this.position.absolute.top - 10, y2 = y1 + 10;
var l = item.left, r = l + item.width,
t = item.top, b = t + item.height;
return ( l < x1 + (this.helperProportions.width / 2) // Right Half
&& x2 - (this.helperProportions.width / 2) < r // Left Half
&& t < y1 + (this.helperProportions.height / 2) // Bottom Half
&& y2 - (this.helperProportions.height / 2) < b ); // Top Half
},
intersectsWithEdge: function(item) {
var y1 = this.position.absolute.top - 10, y2 = y1 + 10;
var t = item.top, b = t + item.height;
if(!this.intersectsWith(item.item.parents(".ui-sortableTree").data("sortableTree").containerCache)) return false;
if (!( t < y1 + (this.helperProportions.height / 2) // Bottom Half
&& y2 - (this.helperProportions.height / 2) < b )) return false; // Top Half
if(y2 > t && y1 < t) return 1; //Crosses top edge
if(y1 < b && y2 > b) return 2; //Crosses bottom edge
return false;
},
refresh: function() {
this.refreshItems();
this.refreshPositions();
},
refreshItems: function() {
this.items = [];
this.containers = [this];
var items = this.items;
var queries = [$(this.options.items, this.element)];
if(this.options.connectWith) {
for (var i = this.options.connectWith.length - 1; i >= 0; i--){
var cur = $(this.options.connectWith[i]);
for (var j = cur.length - 1; j >= 0; j--){
var inst = $.data(cur[j], 'sortableTree');
if(inst && !inst.options.disabled) {
queries.push($(inst.options.items, inst.element));
this.containers.push(inst);
}
};
};
}
for (var i = queries.length - 1; i >= 0; i--){
queries[i].each(function() {
$.data(this, 'sortableTree-item', true); // Data for target checking (mouse manager)
items.push({
item: $(this),
width: 0, height: 0,
left: 0, top: 0
});
});
};
},
refreshPositions: function(fast) {
for (var i = this.items.length - 1; i >= 0; i--){
if(!fast) this.items[i].height = this.items[i].item.outerHeight();
this.items[i].top = this.items[i].item.offset().top;
};
for (var i = this.containers.length - 1; i >= 0; i--){
var p =this.containers[i].element.offset();
this.containers[i].containerCache.left = p.left;
this.containers[i].containerCache.top = p.top;
this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
this.containers[i].containerCache.height= this.containers[i].element.outerHeight();
};
},
destroy: function() {
this.element
.removeClass("ui-sortableTree ui-sortableTree-disabled")
.removeData("sortableTree")
.unbind(".sortableTree");
this.mouseDestroy();
for ( var i = this.items.length - 1; i >= 0; i-- )
this.items[i].item.removeData("sortableTree-item");
},
contactContainers: function(e) {
for (var i = this.containers.length - 1; i >= 0; i--){
if(this.intersectsWith(this.containers[i].containerCache)) {
if(!this.containers[i].containerCache.over) {
if(this.currentContainer != this.containers[i]) {
//When entering a new container, we will find the item with the least distance and append our item near it
var dist = 10000; var itemWithLeastDistance = null; var base = this.position.absolute.top;
for (var j = this.items.length - 1; j >= 0; j--) {
if(!this.containers[i].element[0].contains(this.items[j].item[0])) continue;
var cur = this.items[j].top;
if(Math.abs(cur - base) < dist) {
dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];
}
}
itemWithLeastDistance ? this.rearrange(e, itemWithLeastDistance) : this.rearrange(e, null, this.containers[i].element);
this.propagate("change", e); //Call plugins and callbacks
this.containers[i].propagate("change", e, this); //Call plugins and callbacks
this.currentContainer = this.containers[i];
}
this.containers[i].propagate("over", e, this);
this.containers[i].containerCache.over = 1;
}
} else {
if(this.containers[i].containerCache.over) {
this.containers[i].propagate("out", e, this);
this.containers[i].containerCache.over = 0;
}
}
};
},
mouseStart: function(e,el) {
if(this.options.disabled || this.options.type == 'static') return false;
//Find out if the clicked node (or one of its parents) is a actual item in this.items
var currentItem = null, nodes = $(e.target).parents().each(function() {
if($.data(this, 'sortableTree-item')) {
currentItem = $(this);
return false;
}
});
if($.data(e.target, 'sortableTree-item')) currentItem = $(e.target);
if(!currentItem) return false;
if(this.options.handle) {
var validHandle = false;
$(this.options.handle, currentItem).each(function() { if(this == e.target) validHandle = true; });
if(!validHandle) return false;
}
this.currentItem = currentItem;
var o = this.options;
this.currentContainer = this;
this.refresh();
//Create and append the visible helper
this.helper = typeof o.helper == 'function' ? $(o.helper.apply(this.element[0], [e, this.currentItem])) : this.currentItem.clone();
if(!this.helper.parents('body').length) this.helper.appendTo("body"); //Add the helper to the DOM if that didn't happen already
this.helper.css({ position: 'absolute', clear: 'both' }).addClass('ui-sortableTree-helper'); //Position it absolutely and add a helper class
//Prepare variables for position generation
$.extend(this, {
offsetParent: this.helper.offsetParent(),
offsets: { absolute: this.currentItem.offset() }
});
//Save the first time position
$.extend(this, {
position: {
current: { left: e.pageX, top: e.pageY },
absolute: { left: e.pageX, top: e.pageY },
dom: this.currentItem.prev()[0]
},
clickOffset: { left: -5, top: -5 }
});
this.propagate("start", e); //Call plugins and callbacks
this.helperProportions = { width: this.helper.outerWidth(), height: this.helper.outerHeight() }; //Save and store the helper proportions
for (var i = this.containers.length - 1; i >= 0; i--) {
this.containers[i].propagate("activate", e, this);
} //Post 'activate' events to possible containers
//Prepare possible droppables
if($.ui.ddmanager) $.ui.ddmanager.current = this;
if ($.ui.ddmanager && !o.dropBehaviour) $.ui.ddmanager.prepareOffsets(this, e);
this.dragging = true;
return true;
},
mouseStop: function(e) {
if(this.newPositionAt) this.options.sortIndication.remove.call(this.currentItem, this.newPositionAt); //remove sort indicator
this.propagate("stop", e); //Call plugins and trigger callbacks
//If we are using droppables, inform the manager about the drop
var dropped = ($.ui.ddmanager && !this.options.dropBehaviour) ? $.ui.ddmanager.drop(this, e) : false;
if(!dropped && this.newPositionAt) this.newPositionAt[this.direction == 'down' ? 'before' : 'after'](this.currentItem); //Append to element to its new position
if(this.position.dom != this.currentItem.prev()[0]) this.propagate("update", e); //Trigger update callback if the DOM position has changed
if(!this.element[0].contains(this.currentItem[0])) { //Node was moved out of the current element
this.propagate("remove", e);
for (var i = this.containers.length - 1; i >= 0; i--){
if(this.containers[i].element[0].contains(this.currentItem[0])) {
this.containers[i].propagate("update", e, this);
this.containers[i].propagate("receive", e, this);
}
};
};
//Post events to containers
for (var i = this.containers.length - 1; i >= 0; i--){
this.containers[i].propagate("deactivate", e, this);
if(this.containers[i].containerCache.over) {
this.containers[i].propagate("out", e, this);
this.containers[i].containerCache.over = 0;
}
}
this.dragging = false;
if(this.cancelHelperRemoval) return false;
this.helper.remove();
return false;
},
mouseDrag: function(e) {
//Compute the helpers position
this.position.current = { top: e.pageY + 5, left: e.pageX + 5 };
this.position.absolute = { left: e.pageX + 5, top: e.pageY + 5 };
//Interconnect with droppables
if($.ui.ddmanager) $.ui.ddmanager.drag(this, e);
var intersectsWithDroppable = false;
$.each($.ui.ddmanager.droppables, function() {
if(this.isover) intersectsWithDroppable = true;
});
//Rearrange
if(intersectsWithDroppable) {
if(this.newPositionAt) this.options.sortIndication.remove.call(this.currentItem, this.newPositionAt);
} else {
for (var i = this.items.length - 1; i >= 0; i--) {
if(this.currentItem[0].contains(this.items[i].item[0])) continue;
var intersection = this.intersectsWithEdge(this.items[i]);
if(!intersection) continue;
this.direction = intersection == 1 ? "down" : "up";
this.rearrange(e, this.items[i]);
this.propagate("change", e); //Call plugins and callbacks
break;
}
}
//Post events to containers
this.contactContainers(e);
this.propagate("sort", e); //Call plugins and callbacks
this.helper.css({ left: this.position.current.left+'px', top: this.position.current.top+'px' }); // Stick the helper to the cursor
return false;
},
rearrange: function(e, i, a) {
if(i) {
if(this.newPositionAt) this.options.sortIndication.remove.call(this.currentItem, this.newPositionAt);
this.newPositionAt = i.item;
this.options.sortIndication[this.direction].call(this.currentItem, this.newPositionAt);
} else {
//Append
}
}
}));
$.extend($.ui.sortableTree, {
defaults: {
items: '> *',
zIndex: 1000,
distance: 1
},
getter: "serialize toArray"
});
})(jQuery);