2
0
forked from Wavyzz/dolibarr

Qual: Replace native code with jquery plugin treeview.

This commit is contained in:
Laurent Destailleur
2013-02-19 20:15:30 +01:00
parent 46170c0255
commit 9ddd6215f8
39 changed files with 1230 additions and 1439 deletions

View File

@@ -0,0 +1,36 @@
1.4.1
-----
* Fix for #2360
* Added option cookieOptions: Passed through to $.cookie to set path, domain etc.
* Tested with jQuery 1.2.x and 1.4.3
* Fixed combination of persist: "location" and prerendered: true
1.4
---
* Added changelog (this file)
* Fixed tree control to search only for anchors, allowing images or other elements inside the controls, while keeping the control usable with the keyboard
* Restructured folder layout: root contains plugin resources, lib contains script dependencies, demo contains demos and related files
* Added prerendered option: If set to true, assumes all hitarea divs and classes already rendered, speeding up initialization for big trees, but more obtrusive
* Added jquery.treeview.async.js for ajax-lazy-loading trees, see async.html demo
* Exposed $.fn.treeview.classes for custom classes if necessary
* Show treecontrol only when JavaScript is enabled
* Completely reworked themeing via CSS sprites, resulting in only two files per theme
* updated dotted, black, gray and red theme
* added famfamfam theme (no lines)
* Improved cookie persistence to allow multiple persisted trees per page via cookieId option
* Improved location persistence by making it case-insensitive
* Improved swapClass and replaceClass plugin implementations
* Added folder-closed.gif to filetree example
1.3
---
* Fixes for all outstanding bugs
* Added persistence features
* location based: click on a link in the treeview and reopen that link after the page loaded
* cookie based: save the state of the tree in a cookie on each click and load that on reload
* smoothed animations, fixing flickering in both IE and Opera
* Tested in Firefox 2, IE 6 & 7, Opera 9, Safari 3
* Moved documentation to jQuery wiki
* Requires jQuery 1.2+

View File

@@ -0,0 +1,108 @@
/*
* Async Treeview 0.1 - Lazy-loading extension for Treeview
*
* http://bassistance.de/jquery-plugins/jquery-plugin-treeview/
*
* Copyright 2010 Jörn Zaefferer
* Released under the MIT license:
* http://www.opensource.org/licenses/mit-license.php
*/
;(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,74 @@
.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;
}
.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; }
.filetree span.file { background: url(images/file.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,251 @@
/*
* 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 2010 Jörn Zaefferer
* Released under the MIT license:
* http://www.opensource.org/licenses/mit-license.php
*/
;(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);

View File

@@ -0,0 +1,47 @@
# jQuery Treeview
Lightweight and flexible transformation of an unordered list into an expandable and collapsable tree, great for unobtrusive navigation enhancements. Supports both location and cookie based persistence.
Provides some options for customizing, an async-tree extension and an experimental sortable extension.
![screenshot](https://raw.github.com/jzaefferer/jquery-treeview/master/screenshot.png)
### Note that this project is not actively maintained anymore.
Check out [jqTree](http://mbraak.github.com/jqTree/) for a more up to date plugin.
---
#### [Demo](http://jquery.bassistance.de/treeview/demo/)
#### [Download](https://github.com/jzaefferer/jquery-treeview/zipball/1.4.1)
#### [Changelog](https://raw.github.com/jzaefferer/jquery-treeview/master/changelog.md)
## Todo
### 1.5
- Add classes and rules for root items
- Lazy-loading: render the complete tree, but only apply hitzones and hiding of children to the first level on load
- Async treeview
- Support animations
- Support persist options
## Documentation
```javascript
.treeview( options )
```
Takes an unordered list and makes all branches collapsable. The "treeview" class is added if not already present. To hide branches on first display, mark their li elements with the class "closed". If the "collapsed" option is used, mark initially open branches with class "open".
## License
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB