PortaleOrdiniGruppo/PortalStudio/portalstudio/mif.tree.js
2025-03-24 15:28:26 +01:00

2041 lines
51 KiB
JavaScript

/*
---
name: Mif.Tree
description: Mif.Tree base Class
license: MIT-Style License (http://mifjs.net/license.txt)
copyright: Anton Samoylov (http://mifjs.net)
authors: Anton Samoylov (http://mifjs.net)
requires:
- Core:2.4.5/*
- More/Fx.Scroll
provides: Mif.Tree
...
*/
if(!Mif) var Mif = {};
if(!Mif.ids) Mif.ids = {};
if(!Mif.id) Mif.id = function(id){
return Mif.ids[id];
};
Mif.Tree = new Class({
version: '1.2.6.4.X',
Implements: [ Events, Options],
options:{
types: {},
forest: false,
animateScroll: true,
height: 18,
expandTo: true
},
initialize: function(options){
this.setOptions(options);
Object.append(this, {
types: this.options.types,
forest: this.options.forest,
animateScroll: this.options.animateScroll,
dfltType: this.options.dfltType,
height: this.options.height,
container: document.id(options.container),
UID: ++Mif.Tree.UID,
key: {},
expanded: [],
deletable: this.options.deletable
});
this.defaults = {
name: '',
cls: '',
openIcon: 'mif-tree-empty-icon',
closeIcon: 'mif-tree-empty-icon',
loadable: false,
hidden: false
};
this.dfltState = {
open: false
};
this.$index = [];
this.updateOpenState();
if(this.options.expandTo) this.initExpandTo();
this.DOMidPrefix='mif-tree-';
this.wrapper = new Element('div').addClass('mif-tree-wrapper').inject(this.container);
this.events();
this.initScroll();
this.initSelection();
this.initHover();
this.addEvent('drawChildren', function(parent){
var nodes = parent._toggle||[];
for(var i = 0, l = nodes.length; i < l; i++){
nodes[i].drawToggle();
}
parent._toggle = [];
});
var id = this.options.id;
this.id = id;
if(id != null) Mif.ids[id] = this;
if (this.options.initialize) this.options.initialize.call(this);
},
bound: function(){
Array.each(arguments, function(name){
this.bound[name] = this[name].bind(this);
}, this);
},
events: function(){
this.bound('mouse', 'mouseleave', 'mousedown', 'preventDefault', 'toggleClick', 'toggleDblclick', 'focus', 'blurOnClick', 'keyDown', 'keyUp');
this.wrapper.addEvents({
mousemove: this.bound.mouse,
mouseover: this.bound.mouse,
mouseout: this.bound.mouse,
mouseleave: this.bound.mouseleave,
mousedown: this.bound.mousedown,
click: this.bound.toggleClick,
dblclick: this.bound.toggleDblclick,
selectstart: this.bound.preventDefault
});
this.container.addEvent('click', this.bound.focus);
document.addEvent('click', this.bound.blurOnClick);
document.addEvents({
keydown: this.bound.keyDown,
keyup: this.bound.keyUp
});
},
blurOnClick: function(event){
var target = event.target;
while(target){
if(target == this.container) return;
target = target.parentNode;
}
this.blur();
},
focus: function(){
if(Mif.Focus && Mif.Focus == this) return this;
if(Mif.Focus) Mif.Focus.blur();
Mif.Focus = this;
this.focused = true;
this.container.addClass('mif-tree-focused');
return this.fireEvent('focus');
},
blur: function(){
Mif.Focus = null;
if(!this.focused) return this;
this.focused = false;
this.container.removeClass('mif-tree-focused');
return this.fireEvent('blur');
},
$getIndex: function(){//return array of visible nodes.
this.$index = [];
var node = this.forest ? this.root.getFirst() : this.root;
var previous = node;
while(node){
if(!(previous.hidden && previous.contains(node))){
if(!node.hidden) this.$index.push(node);
previous = node;
}
node = node._getNextVisible();
}
},
preventDefault: function(event){
event.preventDefault();
},
mousedown: function(event){
if(event.rightClick) return;
event.preventDefault();
this.fireEvent('mousedown');
},
mouseleave: function(){
this.mouse.coords = {x: null,y: null};
this.mouse.target = false;
this.mouse.node = false;
if(this.hover) this.hover();
},
mouse: function(event){
this.mouse.coords = this.getCoords(event);
var target = this.getTarget(event);
this.mouse.target = target.target;
this.mouse.node = target.node;
},
getTarget: function(event){
var target = event.target, node;
while(!(/mif-tree/).test(target.className)){
target = target.parentNode;
}
var test = target.className.match(/mif-tree-(gadjet)-[^n]|mif-tree-(icon)|mif-tree-(name)|mif-tree-(checkbox)|mif-tree-(delete)/);
if(!test){
var y = this.mouse.coords.y+this.wrapper.scrollTop;
if(y == -1||!this.$index) {
node = false;
}else{
node = this.$index[((y)/this.height).toInt()];
}
return {
node: node,
target: 'node'
};
}
for(var i = 5; i > 0; i--){
if(test[i]){
var type = test[i];
break;
}
}
return {
node: Mif.Tree.Nodes[target.getAttribute('uid')],
target: type
};
},
getCoords: function(event){
var position = this.wrapper.getPosition();
var x = event.page.x - position.x;
var y = event.page.y - position.y;
var wrapper = this.wrapper;
if((y-wrapper.scrollTop > wrapper.clientHeight)||(x - wrapper.scrollLeft > wrapper.clientWidth)){//scroll line
y = -1;
};
return {x: x, y: y};
},
keyDown: function(event){
this.key = event;
this.key.state = 'down';
if(this.focused) this.fireEvent('keydown', [event]);
},
keyUp: function(event){
this.key = {};
this.key.state = 'up';
if(this.focused) this.fireEvent('keyup', [event]);
},
toggleDblclick: function(event){
var target = this.mouse.target;
if(!(target == 'name' || target == 'icon')) return;
this.mouse.node.toggle();
},
toggleClick: function(event){
if(this.mouse.target != 'gadjet') return;
this.mouse.node.toggle();
},
initScroll: function(){
this.scroll = new Fx.Scroll(this.wrapper, {link: 'cancel'});
},
scrollTo: function(node){
var position = node.getVisiblePosition();
var top = position*this.height;
var up = (top < this.wrapper.scrollTop);
var down = (top > (this.wrapper.scrollTop + this.wrapper.clientHeight - this.height));
if(position == -1 || ( !up && !down ) ) {
this.scroll.fireEvent('complete');
return false;
}
if(this.animateScroll){
this.scroll.start(this.wrapper.scrollLeft, top - (down ? this.wrapper.clientHeight - this.height : this.height));
}else{
this.scroll.set(this.wrapper.scrollLeft, top - (down ? this.wrapper.clientHeight - this.height : this.height));
this.scroll.fireEvent('complete');
}
return this;
},
updateOpenState: function(){
this.addEvents({
'drawChildren': function(parent){
var children = parent.children;
for(var i = 0, l = children.length; i < l; i++){
children[i].updateOpenState();
}
},
'drawRoot': function(){
this.root.updateOpenState();
}
});
},
expandTo: function(node){
if (!node) return this;
var path = [];
while( !node.isRoot() && !(this.forest && node.getParent().isRoot()) ){
node = node.getParent();
if(!node) break;
path.unshift(node);
};
path.each(function(el){
el.toggle(true);
});
return this;
},
initExpandTo: function(){
this.addEvent('loadChildren', function(parent){
if(!parent) return;
var children = parent.children;
for( var i = children.length; i--; ){
var child = children[i];
if(child.expandTo) this.expanded.push(child);
}
});
function expand(){
this.expanded.each(function(node){
this.expandTo(node);
}, this);
this.expanded = [];
};
this.addEvents({
'load': expand.bind(this),
'loadNode': expand.bind(this)
});
}
});
Mif.Tree.UID = 0;
Array.implement({
inject: function(added, current, where){//inject added after or before current;
var pos = this.indexOf(current) + (where == 'before' ? 0 : 1);
for(var i = this.length-1; i >= pos; i--){
this[i + 1] = this[i];
}
this[pos] = added;
return this;
}
});
/*
---
name: Mif.Tree.Node
description: Mif.Tree.Node
license: MIT-Style License (http://mifjs.net/license.txt)
copyright: Anton Samoylov (http://mifjs.net)
authors: Anton Samoylov (http://mifjs.net)
requires: Mif.Tree
provides: Mif.Tree.Node
...
*/
Mif.Tree.Node = new Class({
Implements: [Events],
initialize: function(structure, options) {
Object.append(this, structure);
this.children = [];
this.type = options.type || this.tree.dfltType;
this.property = options.property || {};
this.data = options.data;
this.state = Object.append(Object.clone(this.tree.dfltState), options.state);
this.$calculate();
this.UID = Mif.Tree.Node.UID++;
Mif.Tree.Nodes[this.UID] = this;
var id = this.id;
if(id != null) Mif.ids[id] = this;
this.tree.fireEvent('nodeCreate', [this]);
this._property = ['id', 'name', 'cls', 'openIcon', 'closeIcon', 'openIconUrl', 'closeIconUrl', 'hidden'];
},
$calculate: function(){
Object.append(this, Object.clone(this.tree.defaults));
this.type = Array.convert(this.type);
this.type.each(function(type){
var props = this.tree.types[type];
if(props) Object.append(this, props);
}, this);
Object.append(this, this.property);
return this;
},
getDOM: function(what){
var node = document.id(this.tree.DOMidPrefix+this.UID);
if(what == 'node') return node;
var wrapper = node.getFirst();
if(what == 'wrapper') return wrapper;
if(what == 'children') return wrapper.getNext();
return wrapper.getElement('.mif-tree-'+what);
},
getGadjetType: function(){
return (this.loadable && !this.isLoaded()) ? 'plus' : (this.hasVisibleChildren() ? (this.isOpen() ? 'minus' : 'plus') : 'none');
},
toggle: function(state) {
if(this.state.open == state || this.$loading || this.$toggling) return this;
var parent = this.getParent();
function toggle(type){
this.state.open = !this.state.open;
if(type == 'drawed'){
this.drawToggle();
}else{
parent._toggle = (parent._toggle||[])[this.state.open ? 'include' : 'erase'](this);
}
this.fireEvent('toggle', [this.state.open]);
this.tree.fireEvent('toggle', [this, this.state.open]);
return this;
}
if(parent && !parent.$draw){
return toggle.apply(this, []);
}
if(this.loadable && !this.state.loaded) {
if(!this.load_event){
this.load_event = true;
this.addEvent('load',function(){
this.toggle();
}.bind(this));
}
return this.load();
}
if(!this.hasChildren()) return this;
return toggle.apply(this, ['drawed']);
},
drawToggle: function(){
this.tree.$getIndex();
Mif.Tree.Draw.update(this);
},
recursive: function(fn, args){
args= Array.convert(args);
if(fn.apply(this, args) !== false){
this.children.each(function(node){
if(node.recursive(fn, args) === false){
return false;
}
});
}
return this;
},
isOpen: function(){
return this.state.open;
},
isLoaded: function(){
return this.state.loaded;
},
isLast: function(){
if(this.parentNode == null || this.parentNode.children.getLast() == this) return true;
return false;
},
isFirst: function(){
if(this.parentNode == null || this.parentNode.children[0] == this) return true;
return false;
},
isRoot: function(){
return this.parentNode == null ? true : false;
},
getChildren: function(){
return this.children;
},
hasChildren: function(){
return this.children.length ? true : false;
},
index: function(){
if( this.isRoot() ) return 0;
return this.parentNode.children.indexOf(this);
},
getNext: function(){
if(this.isLast()) return null;
return this.parentNode.children[this.index()+1];
},
getPrevious: function(){
if( this.isFirst() ) return null;
return this.parentNode.children[this.index()-1];
},
getFirst: function(){
if(!this.hasChildren()) return null;
return this.children[0];
},
getLast: function(){
if(!this.hasChildren()) return null;
return this.children.getLast();
},
getParent: function(){
return this.parentNode;
},
_getNextVisible: function(){
var current=this;
if(current.isRoot()){
if(!current.isOpen() || !current.hasChildren(true)) return false;
return current.getFirst(true);
}else{
if(current.isOpen() && current.getFirst(true)){
return current.getFirst(true);
}else{
var parent = current;
do{
current = parent.getNext(true);
if(current) return current;
parent = parent.parentNode;
}while(parent);
return false;
}
}
},
getPreviousVisible: function(){
var index = this.tree.$index.indexOf(this);
return index == 0 ? null : this.tree.$index[index-1];
},
getNextVisible: function(){
var index = this.tree.$index.indexOf(this);
return index < this.tree.$index.length-1 ? this.tree.$index[index+1] : null;
},
getVisiblePosition: function(){
return this.tree.$index.indexOf(this);
},
hasVisibleChildren: function(){
if(!this.hasChildren()) return false;
if(this.isOpen()){
var next = this.getNextVisible();
if(!next) return false;
if(next.parentNode != this) return false;
return true;
}else{
var child = this.getFirst();
while(child){
if(!child.hidden) return true;
child = child.getNext();
}
return false;
}
},
isLastVisible: function(){
var next = this.getNext();
while(next){
if(!next.hidden) return false;
next = next.getNext();
};
return true;
},
contains: function(node){
while(node){
if(node == this) return true;
node = node.parentNode;
};
return false;
},
addType: function(type){
return this.processType(type, 'add');
},
removeType: function(type){
return this.processType(type, 'remove');
},
setType: function(type){
return this.processType(type, 'set');
},
processType: function(type, action){
switch(action){
case 'add': this.type.include(type); break;
case 'remove': this.type.erase(type); break;
case 'set': this.type = type; break;
}
var current = {};
this._property.each(function(p){
current[p] = this[p];
}, this);
this.$calculate();
this._property.each(function(p){
this.updateProperty(p, current[p], this[p]);
}, this);
return this;
},
set: function(obj){
this.tree.fireEvent('beforeSet', [this, obj]);
var property = obj.property||obj||{};
for(var p in property){
var nv = property[p];
var cv = this[p];
this.updateProperty(p, cv, nv);
this[p] = this.property[p] = nv;
}
this.tree.fireEvent('set', [this, obj]);
return this;
},
updateProperty: function(p, cv, nv){
if(nv == cv) return this;
if(p == 'id'){
delete Mif.ids[cv];
if(nv) Mif.ids[nv]=this;
return this;
}
if(!Mif.Tree.Draw.isUpdatable(this)) return this;
switch(p){
case 'name':
this.getDOM('name').innerHTML=nv;
this.getDOM('name').title=nv;
return this;
case 'cls':
this.getDOM('wrapper').removeClass(cv).addClass(nv);
return this;
case 'openIcon':
case 'closeIcon':
this.getDOM('icon').removeClass(cv).addClass(nv);
return this;
case 'openIconUrl':
case 'closeIconUrl':
var icon = this.getDOM('icon');
icon.setStyle('background-image', 'none');
if(nv) icon.setStyle('background-image', 'url('+nv+')');
return this;
case 'hidden':
this.getDOM('node').setStyle('display', nv ? 'none' : 'block');
var _previous = this.getPreviousVisible();
var _next = this.getNextVisible();
var parent = this.getParent();
this[p] = this.property[p]=nv;
this.tree.$getIndex();
var previous = this.getPreviousVisible();
var next = this.getNextVisible();
[_previous, _next, previous, next, parent, this].each(function(node){
Mif.Tree.Draw.update(node);
});
return this;
}
return this;
},
updateOpenState: function(){
if(this.state.open){
this.state.open = false;
this.toggle();
}
}
});
Mif.Tree.Node.UID = 0;
Mif.Tree.Nodes = {};
Mif.Tree.NanoScroll = new Class({
Implements: [Events,Options],
Extends: Mif.Tree,
nanoScroll:false,
initialize: function (options){
this.parent(options);
this.nanoScroll=options.nanoScroll;
if (this.nanoScroll){
this.refreshNanoScroll();
var _this=this;
this.addEvent('toggle', function(){
_this.refreshNanoScroll();
});
this.addEvent('delete', function(){
_this.refreshNanoScroll();
})
}
},
refreshNanoScroll : function(){
if (this.nanoScroll)
this.wrapper.nanoScrollerMT();
}
})
Mif.Tree.Node.implement({
deleteChildren : function () {
for (var i=this.children.length-1; i>=0; i--){
if (!this.children[i].loadable || this.children[i].forceDelete){
var children=this.children[i];
var parent = this, previousVisible = this.children[i].getPreviousVisible();
if(parent) {
parent.children.erase(children);
}else if(!children.tree.forest){
children.tree.root = null;
}
var DOM=children.getDOM('node');
if (DOM)
DOM.destroy();
children.recursive(function(){
if(children.id) delete Mif.ids[children.id];
});
}
}
this.tree.selected=false;
this.tree.$getIndex();
Mif.Tree.Draw.update(parent);
Mif.Tree.Draw.update(previousVisible);
this.tree.mouse.node = false;
this.tree.updateHover();
}
})
/*
Mif.Tree.Search
*/
Mif.Tree.Search = new Class({
Implements: [Events,Options],
Extends: Mif.Tree.NanoScroll,
initialize : function(options){
this.parent(options)
this.searchBtn = new Element('div',{
'class':'mif-tree-btn-search',
}).inject(this.container,'top');
this.searchInput = new Element('input',{
'class':'mif-tree-input-search',
}).inject(this.container,'top');
var _this=this;
this.searchBtn.addEvent('click',function(){ _this.searchStr()})
DOMEvent.defineKey(13, 'enter');
this.searchInput.addEvent('keydown', function(event){
if (event.key == 'enter') _this.searchStr();
});
this.refreshHeight();
},
searchStr:function(){ // fa il filtro sulle 'foglie'
this.fireEvent('initSearch',value)
var value=this.searchInput.get('value');
if (this.root.loadable || this.root.children.length>0){
this.root.toggle(true)
this.filter(this.root,value)
if (value=='')
this.root.toggle(false)
else this.root.toggle(true)
this.$getIndex()
this.refreshNanoScroll();
}
this.fireEvent('searchComplete',value)
},
filter:function(root,value,tempRoot){
if (!tempRoot)
tempRoot=root
for (var i=0; i<root.children.length; i++){
if (root.children[i].loadable || root.children[i].children.length>0){
root.children[i].deleteChildren();
if (value!='' && (root.children[i].loadable || root.children[i].children.length>0)){
json=this.loadOptions(root.children[i],value);
Mif.Tree.Load.children(json.json,root.children[i],root.children[i].tree)
root.children[i].$draw=false;
root.children[i].state.open=true;
Mif.Tree.Draw.update(root.children[i])
if (root.children[i].hasChildren())
root.children[i].getDOM('gadjet').className = 'mif-tree-gadjet mif-tree-gadjet-minus';
}
if (root.children[i].state.open || value==''){
this.filter(root.children[i],value,tempRoot)
}
}
}
if (value==''){
if (root.$draw!=null && root!=tempRoot){
root.state.loaded=false;
root.$draw=false;
root.getDOM('gadjet').className = 'mif-tree-gadjet mif-tree-gadjet-'+root.getGadjetType();
root.toggle(false);
root.$draw=false;
}
}
else {
if (root.children.length>0){
var empty=true;
for (var i=0; i<root.children.length && empty; i++){
empty=root.children[i].loadable && !root.children[i].state.open;
}
if (empty){
root.toggle(false)
}
}
}
},
refreshHeight:function(){
if (this.container.offsetHeight>30)
this.wrapper.style.height=(this.container.offsetHeight-30)+'px'
else
this.wrapper.style.height='0px'
if (this.wrapper.getParent().hasClass('nano'))
this.wrapper.getParent().style.height=this.wrapper.offsetHeight+'px'
}
})
/*
---
name: Mif.Tree.Draw
description: convert javascript tree object to html
license: MIT-Style License (http://mifjs.net/license.txt)
copyright: Anton Samoylov (http://mifjs.net)
authors: Anton Samoylov (http://mifjs.net)
requires: Mif.Tree
provides: Mif.Tree.Draw
...
*/
Mif.Tree.Draw = {
getHTML: function(node,html){
var prefix = node.tree.DOMidPrefix;
var deletable = node.tree.deletable && !node.property.deleteDenied;
var checkbox;
if(node.state.checked != undefined){
if(!node.hasCheckbox) node.state.checked='nochecked';
checkbox = '<span class="mif-tree-checkbox mif-tree-node-'+node.state.checked+'" uid="'+node.UID+'">'+Mif.Tree.Draw.zeroSpace+'</span>';
}else{
checkbox = '';
}
html = html||[];
html.push(
'<div class="mif-tree-node ',(node.isLast() ? 'mif-tree-node-last' : ''),'"'+(node.hidden ? ' style="display:none"' : '')+' id="',prefix,node.UID,'">',
'<span class="mif-tree-node-wrapper ',node.cls,(node.state.selected ? ' mif-tree-node-selected' : ''),'" uid="',node.UID,'">',
'<span class="mif-tree-gadjet mif-tree-gadjet-',node.getGadjetType(),'" uid="',node.UID,'">',Mif.Tree.Draw.zeroSpace,'</span>',
checkbox,
'<span class="mif-tree-icon ',(node.closeIconUrl?'" style="background-image: url('+node.closeIconUrl+')" ': node.closeIcon+'"'),' uid="',node.UID,'">',Mif.Tree.Draw.zeroSpace,'</span>',
'<span class="mif-tree-name" uid="',node.UID,'" title="',node.name,'">',node.name,'</span>',
(deletable ? '<span class="mif-tree-delete" uid="' : '') ,
(deletable ? node.UID : '' ),
(deletable ? '"></span>' : ''),
'</span>',
'<div class="mif-tree-children" style="display:none"></div>',
'</div>'
);
return html;
},
children: function(parent, container){
parent.open = true;
parent.$draw = true;
var html = [];
var children = parent.children;
for(var i = 0, l = children.length; i < l; i++){
this.getHTML(children[i], html);
}
container = container || parent.getDOM('children');
container.set('html', html.join(''));
parent.tree.fireEvent('drawChildren',[parent]);
},
root: function(tree){
var domRoot = this.node(tree.root);
domRoot.inject(tree.wrapper);
tree.$draw = true;
tree.fireEvent('drawRoot');
},
forestRoot: function(tree){
var container = new Element('div').addClass('mif-tree-children-root').inject(tree.wrapper);
Mif.Tree.Draw.children(tree.root, container);
},
node: function(node){
return new Element('div').set('html', this.getHTML(node).join('')).getFirst();
},
isUpdatable: function(node){
if(
(!node||!node.tree) ||
(node.getParent() && !node.getParent().$draw) ||
(node.isRoot() && (!node.tree.$draw||node.tree.forest))
) return false;
return true;
},
update: function(node){
if(!this.isUpdatable(node)) return null;
if(!node.hasChildren()) node.state.open = false;
node.getDOM('gadjet').className = 'mif-tree-gadjet mif-tree-gadjet-'+node.getGadjetType();
if (node.closeIconUrl) {
node.getDOM('icon').setStyle('background-image', 'url('+(node.isOpen() ? node.openIconUrl : node.closeIconUrl)+')');
} else {
node.getDOM('icon').className = 'mif-tree-icon '+node[node.isOpen() ? 'openIcon' : 'closeIcon'];
}
node.getDOM('node')[(node.isLastVisible() ?'add' : 'remove')+'Class']('mif-tree-node-last');
if(node.$loading) return null;
var children = node.getDOM('children');
if(node.isOpen()){
if(!node.$draw) Mif.Tree.Draw.children(node);
children.style.display = 'block';
}else{
children.style.display = 'none';
}
node.tree.fireEvent('updateNode', node);
return node;
},
inject: function(node, element){
if(!this.isUpdatable(node)) return;
element = element || node.getDOM('node') || this.node(node);
var previous = node.getPrevious();
if(previous){
element.inject(previous.getDOM('node'),'after');
return;
}
var container;
if(node.tree.forest && node.parentNode.isRoot()){
container = node.tree.wrapper.getElement('.mif-tree-children-root');
}else if(node.tree.root == node){
container = node.tree.wrapper;
}else{
container = node.parentNode.getDOM('children');
}
element.inject(container, 'top');
}
};
Mif.Tree.Draw.zeroSpace = Browser.ie ? '&shy;' : (Browser.chrome || Browser.safari ? '&#8203' : '');
/*
---
name: Mif.Tree.Selection
description: tree nodes selection
license: MIT-Style License (http://mifjs.net/license.txt)
copyright: Anton Samoylov (http://mifjs.net)
authors: Anton Samoylov (http://mifjs.net)
requires: Mif.Tree
provides: Mif.Tree.Selection
...
*/
Mif.Tree.implement({
initSelection: function(){
this.defaults.selectClass = '';
var _this = this;
this.wrapper.addEvent('click', function(e){ _this.attachSelect.call(_this,e)});
},
attachSelect: function(event){
if(!['icon', 'name', 'node', 'delete'].contains(this.mouse.target)) return;
var node = this.mouse.node;
if(!node) return;
if(this.mouse.target == 'delete'){
node._delete();
}else
this.select(node);
},
select: function(node) {
if(!node) return this;
var current = this.selected;
if (current == node) return this;
if (current) {
current.select(false);
this.fireEvent('unSelect', [current]).fireEvent('selectChange', [current, false]);
}
this.selected = node;
node.select(true);
this.fireEvent('select', [node]).fireEvent('selectChange', [node, true]);
return this;
},
unselect: function(){
var current = this.selected;
if(!current) return this;
this.selected = false;
current.select(false);
this.fireEvent('unSelect', [current]).fireEvent('selectChange', [current, false]);
return this;
},
getSelected: function(){
return this.selected;
},
isSelected: function(node){
return node.isSelected();
}
});
Mif.Tree.Node.implement({
select: function(state) {
this.state.selected = state;
if(!Mif.Tree.Draw.isUpdatable(this)) return;
var wrapper=this.getDOM('wrapper');
wrapper[(state ? 'add' : 'remove')+'Class'](this.selectClass||'mif-tree-node-selected');
},
isSelected: function(){
return this.state.selected;
}
});
/*
---
name: Mif.Tree.Hover
description: hover(mouseover/mouseout) events/effects
license: MIT-Style License (http://mifjs.net/license.txt)
copyright: Anton Samoylov (http://mifjs.net)
authors: Anton Samoylov (http://mifjs.net)
requires: Mif.Tree
provides: Mif.Tree.Hover
...
*/
Mif.Tree.implement({
initHover: function(){
this.defaults.hoverClass = '';
this.wrapper.addEvent('mousemove', this.hover.bind(this));
this.wrapper.addEvent('mouseout', this.hover.bind(this));
this.defaultHoverState = {
gadjet: false,
checkbox: false,
icon: false,
name: false,
node: false
};
this.hoverState = Object.clone(this.defaultHoverState);
},
hover: function(){
var cnode = this.mouse.node;
var ctarget = this.mouse.target;
Object.each(this.hoverState, function(node, target, state){
if(node == cnode && (target == 'node'||target==ctarget)) return;
if(node) {
Mif.Tree.Hover.out(node, target);
state[target] = false;
this.fireEvent('hover', [node, target, 'out']);
}
if(cnode && (target == 'node'||target == ctarget)) {
Mif.Tree.Hover.over(cnode, target);
state[target] = cnode;
this.fireEvent('hover', [cnode, target, 'over']);
}else{
state[target] = false;
}
}, this);
},
updateHover: function(){
this.hoverState = Object.clone(this.defaultHoverState);
this.hover();
}
});
Mif.Tree.Hover = {
over: function(node, target){
var wrapper = node.getDOM('wrapper');
wrapper.addClass((node.hoverClass||'mif-tree-hover')+'-'+target);
if(node.state.selected) wrapper.addClass((node.hoverClass||'mif-tree-hover')+'-selected-'+target);
},
out: function(node, target){
var wrapper = node.getDOM('wrapper');
wrapper.removeClass((node.hoverClass||'mif-tree-hover')+'-'+target).removeClass((node.hoverClass||'mif-tree-hover')+'-selected-'+target);
}
};
/*
---
name: Mif.Tree.Load
description: load tree from json
license: MIT-Style License (http://mifjs.net/license.txt)
copyright: Anton Samoylov (http://mifjs.net)
authors: Anton Samoylov (http://mifjs.net)
requires: Mif.Tree
provides: Mif.Tree.Load
...
*/
Mif.Tree.Load = {
children: function(children, parent, tree){
var i, l;
var subChildrens = [];
for(i = children.length; i--; ){
var child = children[i];
var node = new Mif.Tree.Node({
tree: tree,
parentNode: parent||undefined
}, child);
if( tree.forest || parent != undefined){
parent.children.unshift(node);
}else{
tree.root = node;
}
var subChildren = child.children;
if(subChildren && subChildren.length){
subChildrens.push({children: subChildren, parent: node});
}
}
for(i = 0, l = subChildrens.length; i < l; i++) {
var sub = subChildrens[i];
arguments.callee(sub.children, sub.parent, tree);
}
if(parent) parent.state.loaded = true;
tree.fireEvent('loadChildren', parent);
}
};
Mif.Tree.implement({
load: function(options){
var tree = this;
this.loadOptions = this.loadOptions|| Function.from({});
function success(json){
var parent = null;
if(tree.forest){
tree.root = new Mif.Tree.Node({
tree: tree,
parentNode: null
}, {});
parent = tree.root;
}
Mif.Tree.Load.children(json, parent, tree);
Mif.Tree.Draw[tree.forest ? 'forestRoot' : 'root'](tree);
tree.$getIndex();
tree.fireEvent('load');
return tree;
}
options = Object.append(Object.append({
isSuccess: Function.from(true),
secure: true,
onSuccess: success,
method: 'get'
}, this.loadOptions()), options);
if(options.json) return success(options.json);
new Request.JSON(options).send();
return this;
}
});
Mif.Tree.Node.implement({
load: function(options){
this.$loading = true;
options = options||{};
this.addType('loader');
var self = this;
function success(json){
Mif.Tree.Load.children(json, self, self.tree);
delete self.$loading;
self.state.loaded = true;
self.removeType('loader');
Mif.Tree.Draw.update(self);
self.fireEvent('load');
self.tree.fireEvent('loadNode', self);
return self;
}
options=Object.append(Object.append(Object.append({
isSuccess: Function.from(true),
secure: true,
onSuccess: success,
method: 'get'
}, this.tree.loadOptions(this)), this.loadOptions), options);
if(options.json) return success(options.json);
new Request.JSON(options).send();
return this;
}
});
/*
---
name: Mif.Tree.Sort
description: Mif.Tree.Sort
license: MIT-Style License (http://mifjs.net/license.txt)
copyright: Anton Samoylov (http://mifjs.net)
authors: Anton Samoylov (http://mifjs.net)
requires: Mif.Tree
provides: Mif.Tree.Sort
...
*/
Mif.Tree.implement({
initSortable: function(sortFunction){
this.sortable = true;
this.sortFunction = sortFunction||function(node1, node2){
if(node1.name > node2.name){
return 1;
}else if(node1.name < node2.name){
return -1;
}else{
return 0;
}
};
this.addEvent('loadChildren', function(parent){
if(parent) parent.sort();
});
this.addEvent('structureChange', function(from, to, where, type){
from.sort();
});
return this;
}
});
Mif.Tree.Node.implement({
sort: function(sortFunction){
this.children.sort(sortFunction||this.tree.sortFunction);
return this;
}
});
/*
---
name: Mif.Tree.Transform
description: implement move/copy/del/add actions
license: MIT-Style License (http://mifjs.net/license.txt)
copyright: Anton Samoylov (http://mifjs.net)
authors: Anton Samoylov (http://mifjs.net)
requires: Mif.Tree
provides: Mif.Tree.Transform
...
*/
Mif.Tree.Node.implement({
inject: function(node, where, element){//element - internal property
where = where||'inside';
var parent = this.parentNode;
function getPreviousVisible(node){
var previous = node;
while(previous){
previous = previous.getPrevious();
if(!previous) return null;
if(!previous.hidden) return previous;
}
return null;
}
var previousVisible = getPreviousVisible(this);
var type = element ? 'copy' : 'move';
switch(where){
case 'after':
case 'before':
if( node['get' + (where == 'after' ? 'Next' : 'Previous')]() == this ) return false;
if(this.parentNode) {
this.parentNode.children.erase(this);
}
this.parentNode = node.parentNode;
this.parentNode.children.inject(this, node, where);
break;
case 'inside':
if( node.tree && node.getLast() == this ) return false;
if(this.parentNode) {
this.parentNode.children.erase(this);
}
if(node.tree){
if(!node.hasChildren()){
node.$draw = true;
node.state.open = true;
}
node.children.push(this);
this.parentNode = node;
}else{
node.root = this;
this.parentNode = null;
node.fireEvent('drawRoot');
}
break;
}
var tree = node.tree || node;
if(this == this.tree.root){
this.tree.root = false;
}
if(this.tree != tree){
var oldTree = this.tree;
this.recursive(function(){
this.tree = tree;
});
};
tree.fireEvent('structureChange', [this, node, where, type]);
tree.$getIndex();
if(oldTree) oldTree.$getIndex();
Mif.Tree.Draw.inject(this, element);
[node, this, parent, previousVisible, getPreviousVisible(this)].each(function(node){
Mif.Tree.Draw.update(node);
});
return this;
},
copy: function(node, where){
if (this.copyDenied) return this;
function copy(structure){
var node = structure.node;
var tree = structure.tree;
var options = Object.clone({
property: node.property,
type: node.type,
state: node.state,
data: node.data
});
options.state.open = false;
var nodeCopy = new Mif.Tree.Node({
parentNode: structure.parentNode,
children: [],
tree: tree
}, options);
node.children.each(function(child){
var childCopy = copy({
node: child,
parentNode: nodeCopy,
tree: tree
});
nodeCopy.children.push(childCopy);
});
return nodeCopy;
};
var nodeCopy = copy({
node: this,
parentNode: null,
tree: node.tree
});
return nodeCopy.inject(node, where, Mif.Tree.Draw.node(nodeCopy));
},
remove: function(){
if (this.removeDenied) return;
this.tree.fireEvent('remove', [this]);
var parent = this.parentNode, previousVisible = this.getPreviousVisible();
if(parent) {
parent.children.erase(this);
}else if(!this.tree.forest){
this.tree.root = null;
}
this.tree.selected = false;
this.getDOM('node').destroy();
this.tree.$getIndex();
Mif.Tree.Draw.update(parent);
Mif.Tree.Draw.update(previousVisible);
this.recursive(function(){
if(this.id) delete Mif.ids[this.id];
});
this.tree.mouse.node = false;
this.tree.updateHover();
}
});
Mif.Tree.implement({
move: function(from, to, where){
if(from.inject(to, where)){
this.fireEvent('move', [from, to, where]);
}
return this;
},
copy: function(from, to, where){
var copy = from.copy(to, where);
if(copy){
this.fireEvent('copy', [from, to, where, copy]);
}
return this;
},
remove: function(node){
node.remove();
return this;
},
add: function(node, current, where){
if(!(node instanceof Mif.Tree.Node)){
node = new Mif.Tree.Node({
parentNode: null,
tree: this
}, node);
};
node.inject(current, where, Mif.Tree.Draw.node(node));
this.fireEvent('add', [node, current, where]);
return this;
}
});
/*
---
name: Mif.Tree.Drag
description: implements drag and drop
license: MIT-Style License (http://mifjs.net/license.txt)
copyright: Anton Samoylov (http://mifjs.net)
authors: Anton Samoylov (http://mifjs.net)
requires: [Mif.Tree, Mif.Tree.Transform, more:/Drag.Move]
provides: Mif.Tree.Drag
...
*/
Mif.Tree.Drag = new Class({
Implements: [ Events, Options],
Extends: Drag,
options:{
group: 'tree',
droppables: [],
snap: 4,
animate: true,
open: 600,//time to open node
scrollDelay: 100,
scrollSpeed: 100,
modifier: 'control',//copy
startPlace: ['icon', 'name'],
allowContainerDrop: true
},
initialize: function(tree, options){
tree.drag = this;
this.setOptions(options);
Object.append(this, {
tree: tree,
snap: this.options.snap,
groups: [],
droppables: [],
action: this.options.action
});
this.addToGroups(this.options.group);
this.setDroppables(this.options.droppables);
Object.append(tree.defaults, {
dropDenied: [],
dragDisabled: false
});
tree.addEvent('drawRoot',function(){
tree.root.dropDenied.combine(['before', 'after']);
});
this.pointer = new Element('div').addClass('mif-tree-pointer').inject(tree.wrapper);
this.current = Mif.Tree.Drag.current;
this.target = Mif.Tree.Drag.target;
this.where = Mif.Tree.Drag.where;
this.element = [this.current, this.target, this.where];
this.document = tree.wrapper.getDocument();
this.selection = (Browser.ie) ? 'selectstart' : 'mousedown';
this.bound = {
start: this.start.bind(this),
check: this.check.bind(this),
drag: this.drag.bind(this),
stop: this.stop.bind(this),
cancel: this.cancel.bind(this),
eventStop: Function.from(false),
leave: this.leave.bind(this),
enter: this.enter.bind(this),
keydown: this.keydown.bind(this)
};
this.attach();
this.addEvent('start', function(){
Mif.Tree.Drag.dropZone=this;
this.tree.unselect();
document.addEvent('keydown', this.bound.keydown);
this.setDroppables();
this.droppables.each(function(item){
item.getElement().addEvents({mouseleave: this.bound.leave, mouseenter: this.bound.enter});
}, this);
Mif.Tree.Drag.current.getDOM('name').addClass('mif-tree-drag-current');
this.addGhost();
}, true);
this.addEvent('complete', function(){
document.removeEvent('keydown', this.bound.keydown);
this.droppables.each(function(item){
item.getElement().removeEvent('mouseleave', this.bound.leave).removeEvent('mouseenter', this.bound.enter);
}, this);
Mif.Tree.Drag.current.getDOM('name').removeClass('mif-tree-drag-current');
var dropZone = Mif.Tree.Drag.dropZone;
if(!dropZone || dropZone.where=='notAllowed'){
Mif.Tree.Drag.startZone.onstop();
Mif.Tree.Drag.startZone.emptydrop();
return;
}
if(dropZone.onstop) dropZone.onstop();
dropZone.beforeDrop();
});
},
getElement: function(){
return this.tree.wrapper;
},
addToGroups: function(groups){
groups = Array.convert(groups);
this.groups.combine(groups);
groups.each(function(group){
Mif.Tree.Drag.groups[group]=(Mif.Tree.Drag.groups[group]||[]).include(this);
}, this);
},
setDroppables: function(droppables){
this.droppables.combine(Array.convert(droppables));
this.groups.each(function(group){
this.droppables.combine(Mif.Tree.Drag.groups[group]);
}, this);
},
attach: function(){
this.tree.wrapper.addEvent('mousedown', this.bound.start);
return this;
},
detach: function(){
this.tree.wrapper.removeEvent('mousedown', this.bound.start);
return this;
},
dragTargetSelect: function(){
function addDragTarget(){
this.current.getDOM('name').addClass('mif-tree-drag-current');
}
function removeDragTarget(){
this.current.getDOM('name').removeClass('mif-tree-drag-current');
}
this.addEvent('start',addDragTarget.bind(this));
this.addEvent('beforeComplete',removeDragTarget.bind(this));
},
leave: function(event){
var dropZone = Mif.Tree.Drag.dropZone;
if(dropZone){
dropZone.where = 'notAllowed';
Mif.Tree.Drag.ghost.firstChild.className = 'mif-tree-ghost-icon mif-tree-ghost-'+dropZone.where;
if(dropZone.onleave) dropZone.onleave();
Mif.Tree.Drag.dropZone = false;
}
var relatedZone = this.getZone(event.relatedTarget);
if(relatedZone) this.enter(null, relatedZone);
},
onleave: function(){
this.tree.unselect();
this.clean();
window.clearTimeout(this.scrolling);
this.scrolling = null;
this.target = false;
},
enter: function(event, zone){
if(event) zone = this.getZone(event.target);
var dropZone = Mif.Tree.Drag.dropZone;
if(dropZone && dropZone.onleave) dropZone.onleave();
Mif.Tree.Drag.dropZone = zone;
zone.current = Mif.Tree.Drag.current;
if(zone.onenter) zone.onenter();
},
onenter: function(){
this.onleave();
},
getZone: function(target){//private leave/enter
if(!target) return false;
var parent = document.id(target);
do{
for(var l = this.droppables.length;l--;){
var zone = this.droppables[l];
if( parent == zone.getElement() ) {
return zone;
}
}
parent = parent.getParent();
}while(parent);
return false;
},
keydown: function(event){
if(event.key == 'esc') {
var zone = Mif.Tree.Drag.dropZone;
if(zone) zone.where = 'notAllowed';
this.stop(event);
}
},
autoScroll: function(){
var y = this.y;
if(y == -1) return;
var wrapper = this.tree.wrapper;
var top = y-wrapper.scrollTop;
var bottom = wrapper.offsetHeight-top;
var sign = 0;
var delta;
if(top < this.tree.height){
delta = top;
sign = 1;
}else if(bottom < this.tree.height){
delta = bottom;
sign = -1;
}
if(sign && !this.scrolling){
this.scrolling = function(node){
if(y != this.y){
y = this.y;
delta = (sign == 1 ? (y - wrapper.scrollTop) : (wrapper.offsetHeight - y + wrapper.scrollTop)) || 1;
}
wrapper.scrollTop = wrapper.scrollTop - sign*this.options.scrollSpeed/delta;
}.periodical(this.options.scrollDelay, this, [sign]);
}
if(!sign){
window.clearTimeout(this.scrolling);
this.scrolling = null;
}
},
start: function(event){//mousedown
if(event.rightClick) return;
if (this.options.preventDefault) event.preventDefault();
this.fireEvent('beforeStart', this.element);
var target = this.tree.mouse.target;
if(!target) return;
this.current = Array.convert(this.options.startPlace).contains(target) ? this.tree.mouse.node : false;
if(!this.current || this.current.dragDisabled) {
return;
}
Mif.Tree.Drag.current = this.current;
Mif.Tree.Drag.startZone = this;
this.mouse = {start: event.page};
this.document.addEvents({mousemove: this.bound.check, mouseup: this.bound.cancel});
this.document.addEvent(this.selection, this.bound.eventStop);
},
drag: function(event){
Mif.Tree.Drag.ghost.position({x:event.page.x+20,y:event.page.y+20});
var dropZone = Mif.Tree.Drag.dropZone;
if(!dropZone||!dropZone.ondrag) return;
Mif.Tree.Drag.dropZone.ondrag(event);
},
ondrag: function(event){
this.autoScroll();
if(!this.checkTarget()) return;
this.clean();
var where = this.where;
var target = this.target;
var ghostType = where;
if(where == 'after' && target && (target.getNext()) || where == 'before' && target.getPrevious()){
ghostType = 'between';
}
Mif.Tree.Drag.ghost.firstChild.className = 'mif-tree-ghost-icon mif-tree-ghost-' + ghostType;
if(where == 'notAllowed'){
this.tree.unselect();
return;
}
if(target && target.tree) this.tree.select(target);
if(where == 'inside'){
if(target.tree && !target.isOpen() && !this.openTimer && (target.loadable || target.hasChildren()) ){
this.wrapper = target.getDOM('wrapper').setStyle('cursor', 'progress');
this.openTimer = function(){
target.toggle();
this.clean();
}.delay(this.options.open,this);
}
}else{
var wrapper = this.tree.wrapper;
var top = this.index*this.tree.height;
if(where == 'after') top += this.tree.height;
this.pointer.setStyles({
left: wrapper.scrollLeft,
top: top,
width: wrapper.clientWidth
});
}
},
clean: function(){
this.pointer.style.width = 0;
if(this.openTimer){
window.clearTimeout(this.openTimer);
this.openTimer = false;
this.wrapper.style.cursor = 'inherit';
this.wrapper = false;
}
},
addGhost: function(){
var wrapper = this.current.getDOM('wrapper');
var ghost = new Element('span').addClass('mif-tree-ghost');
ghost.adopt(Mif.Tree.Draw.node(this.current).getFirst())
.inject(document.body).addClass('mif-tree-ghost-notAllowed').setStyle('position', 'absolute');
new Element('span').set('html',Mif.Tree.Draw.zeroSpace).inject(ghost,'top');
ghost.getLast().getFirst().className = '';
Mif.Tree.Drag.ghost = ghost;
},
checkTarget: function(){
this.y = this.tree.mouse.coords.y;
var target = this.tree.mouse.node;
if(!target){
if(this.options.allowContainerDrop && (this.tree.forest || !this.tree.root)){
this.target = this.tree.$index.getLast();
this.index = this.tree.$index.length-1;
if(this.index == -1){
this.where = 'inside';
this.target = this.tree.root || this.tree;
}else{
this.where = 'after';
}
}else{
this.target = false;
this.where = 'notAllowed';
}
this.fireEvent('drag');
return true;
};
if((this.current instanceof Mif.Tree.Node) && this.current.contains(target)){
this.target = target;
this.where = 'notAllowed';
this.fireEvent('drag');
return true;
};
this.index = Math.floor(this.y/this.tree.height);
var delta = this.y - this.index*this.tree.height;
var deny = target.dropDenied;
if(this.tree.sortable){
deny.include('before').include('after');
};
var where;
if(!deny.contains('inside') && delta > (this.tree.height/4) && delta < (3/4*this.tree.height)){
where = 'inside';
}else{
if(delta < this.tree.height/2){
if(deny.contains('before')){
if(deny.contains('inside')){
where = deny.contains('after') ? 'notAllowed' : 'after';
}else{
where = 'inside';
}
}else{
where = 'before';
}
}else{
if(deny.contains('after')){
if(deny.contains('inside')){
where = deny.contains('before') ? 'notAllowed' : 'before';
}else{
where = 'inside';
}
}else{
where = 'after';
}
}
};
if(this.where == where && this.target == target) return false;
this.where = where;
this.target = target;
this.fireEvent('drag');
return true;
},
emptydrop: function(){
var current = this.current, target = this.target, where = this.where;
var scroll = this.tree.scroll;
var complete = function(){
scroll.removeEvent('complete', complete);
if(this.options.animate){
var wrapper = current.getDOM('wrapper');
var position = wrapper.getPosition();
Mif.Tree.Drag.ghost.set('morph',{
duration: 'short',
onComplete: function(){
Mif.Tree.Drag.ghost.dispose();
this.fireEvent('emptydrop', this.element);
}.bind(this)
});
Mif.Tree.Drag.ghost.morph({left: position.x, top: position.y});
return;
};
Mif.Tree.Drag.ghost.dispose();
this.fireEvent('emptydrop', this.element);
return;
}.bind(this);
scroll.addEvent('complete', complete);
this.tree.select(this.current);
this.tree.scrollTo(this.current);
},
beforeDrop: function(){
if(this.options.beforeDrop){
this.options.beforeDrop.apply(this, [this.current, this.target, this.where]);
}else{
this.drop();
}
},
drop: function(){
var current = this.current, target = this.target, where = this.where;
Mif.Tree.Drag.ghost.dispose();
var action = this.action || (this.tree.key[this.options.modifier] ? 'copy' : 'move');
if(this.where == 'inside' && target.tree && !target.isOpen()){
if(target.tree) target.toggle();
if(target.$loading){
var onLoad = function(){
this.tree[action](current, target, where);
this.tree.select(current).scrollTo(current);
this.fireEvent('drop', [current, target, where]);
target.removeEvent('load',onLoad);
};
target.addEvent('load',onLoad);
return;
};
};
if(!(current instanceof Mif.Tree.Node )){
current = current.toNode(this.tree);
}
this.tree[action](current, target, where);
this.tree.select(current).scrollTo(current);
this.fireEvent('drop', [current, target, where]);
},
onstop: function(){
this.clean();
window.clearTimeout(this.scrolling);
}
});
Mif.Tree.Drag.groups={};
/*
---
name: Mif.Tree.Rename
description: Mif.Tree.Rename
license: MIT-Style License (http://mifjs.net/license.txt)
copyright: Anton Samoylov (http://mifjs.net)
authors: Anton Samoylov (http://mifjs.net)
requires: Mif.Tree
provides: Mif.Tree.Rename
...
*/
Mif.Tree.implement({
attachRenameEvents: function(){
this.wrapper.addEvents({
click: function(event){
if(document.id(event.target).get('tag') == 'input') return;
this.beforeRenameComplete();
}.bind(this),
keydown: function(event){
if(event.key == 'enter'){
this.beforeRenameComplete();
}
if(event.key == 'esc'){
this.renameCancel();
}
}.bind(this)
});
},
disableEvents: function(){
if(!this.eventStorage) this.eventStorage = new Element('div');
this.eventStorage.cloneEvents(this.wrapper);
this.wrapper.removeEvents();
},
enableEvents: function(){
this.wrapper.removeEvents();
this.wrapper.cloneEvents(this.eventStorage);
},
getInput: function(){
if(!this.input){
this.input = new Element('input').addClass('mif-tree-rename');
this.input.addEvent('focus',function(){this.select();}).addEvent('click', function(event) {
event.stop();
});
Mif.Tree.Rename.autoExpand(this.input);
}
return this.input;
},
startRename: function(node){
this.focus();
this.unselect();
this.disableEvents();
this.attachRenameEvents();
var input = this.getInput();
input.value = node.name;
this.renameName = node.getDOM('name');
this.renameNode = node;
input.setStyle('width', this.renameName.offsetWidth+15);
input.replaces(this.renameName);
input.focus();
},
finishRename: function(){
this.renameName.replaces(this.getInput());
},
beforeRenameComplete: function(){
if(this.options.beforeRename){
var newName = this.getInput().value;
var node = this.renameNode;
this.options.beforeRename.apply(this, [node, node.name, newName]);
}else{
this.renameComplete();
}
},
renameComplete: function(){
this.enableEvents();
this.finishRename();
var node = this.renameNode;
var oldName = node.name;
node.set({
property:{
name: this.getInput().value
}
});
this.fireEvent('rename', [node, node.name, oldName]);
this.select(node);
},
renameCancel: function(){
this.enableEvents();
this.finishRename();
this.select(this.renameNode);
}
});
Mif.Tree.Node.implement({
rename: function(){
if (this.property.renameDenied) return;
this.tree.startRename(this);
}
});
Mif.Tree.Rename={
autoExpand: function(input){
var span = new Element('span').addClass('mif-tree-rename').setStyles({
position: 'absolute',
left: -2000,
top:0,
padding: 0
}).inject(document.body);
input.addEvent('keydown',function(event){
(function(){
input.setStyle('width',Math.max(20, span.set('html', input.value.replace(/\s/g,'&nbsp;')).offsetWidth+15));
}).delay(10);
});
}
};
/*
---
name: Mif.Tree.Delete
description: Mif.Tree.Delete
license: MIT-Style License (http://mifjs.net/license.txt)
copyright: Anton Samoylov (http://mifjs.net)
authors: Anton Samoylov (http://mifjs.net)
requires: Mif.Tree
provides: Mif.Tree.Delete
...
*/
Mif.Tree.implement({
startDelete: function(node){
node.deleteCondition = true;
this.beforeDelete(node);
this.afterDelete(node);
},
beforeDelete: function(node){
if( !node || node.tree.root == node ) return false;
this.fireEvent('beforeDelete',[node])
},
afterDelete: function(node){
if( node.deleteCondition ){
node.remove();
this.fireEvent('delete',[node])
}else{
this.fireEvent('deleteDenied',[node])
}
}
})
Mif.Tree.Node.implement({
_delete: function(){
if (this.property.deleteDenied) return;
this.tree.startDelete(this);
}
});