/************************************************************************************************************ (C) www.dhtmlgoodies.com, July 2006 Update log: This is a script from www.dhtmlgoodies.com. You will find this and a lot of other scripts at our website. Terms of use: You are free to use this script as long as the copyright message is kept intact. However, you may not redistribute, sell or repost it without our permission. Thank you! www.dhtmlgoodies.com Alf Magne Kalleland ************************************************************************************************************/ var JSTreeObj; var treeUlCounter = 0; var nodeId = 1; /* Constructor */ function JSDragDropTree() { var idOfTree; var imageFolder; var folderImage; var leafImage; var plusImage; var minusImage; var blankImage; var maximumDepth; var dragNode_source; var dragNode_parent; var dragNode_sourceNextSib; var dragNode_noSiblings; var dragNode_noChildren; var dragNode_destination; var floatingContainer; var dragDropTimer; var dropTargetIndicator; var insertAsSub; var indicator_offsetX; var indicator_offsetX_sub; var indicator_offsetY; var onComplete; var onError; var saveUrl; var saveParameter; var fieldId; var includeImage; var movedClass; var allowDrag; this.saveParameter = 'saveString'; this.allowDrag = true; this.imageFolder = 'images/'; this.folderImage = 'folder.gif'; this.leafImage = 'sheet.gif' this.plusImage = 'plus.gif'; this.minusImage = 'minus.gif'; this.blankImage = 'blank.gif'; this.maximumDepth = 10000; this.includeImage = true; var messageMaximumDepthReached; var ajaxObjects; this.floatingContainer = document.createElement('UL'); this.floatingContainer.style.position = 'absolute'; this.floatingContainer.style.display='none'; this.floatingContainer.id = 'floatingContainer'; this.insertAsSub = false; document.body.appendChild(this.floatingContainer); this.dragDropTimer = -1; this.dragNode_noSiblings = false; if(document.all){ this.indicator_offsetX = 2; // Offset position of small black lines indicating where nodes would be dropped. this.indicator_offsetX_sub = 4; this.indicator_offsetY = 2; }else{ this.indicator_offsetX = 1; // Offset position of small black lines indicating where nodes would be dropped. this.indicator_offsetX_sub = 3; this.indicator_offsetY = 2; } if(navigator.userAgent.indexOf('Opera')>=0){ this.indicator_offsetX = 2; // Offset position of small black lines indicating where nodes would be dropped. this.indicator_offsetX_sub = 3; this.indicator_offsetY = -7; } this.messageMaximumDepthReached = ''; // Use '' if you don't want to display a message this.ajaxObjects = new Array(); } /* JSDragDropTree class */ JSDragDropTree.prototype = { Get_Cookie : function(name) { var start = document.cookie.indexOf(name+"="); var len = start+name.length+1; if ((!start) && (name != document.cookie.substring(0,name.length))) return null; if (start == -1) return null; var end = document.cookie.indexOf(";",len); if (end == -1) end = document.cookie.length; return unescape(document.cookie.substring(len,end)); } , // This function has been slightly modified Set_Cookie : function(name,value,expires,path,domain,secure) { expires = expires * 60*60*24*1000; var today = new Date(); var expires_date = new Date( today.getTime() + (expires) ); var cookieString = name + "=" +escape(value) + ( (expires) ? ";expires=" + expires_date.toGMTString() : "") + ( (path) ? ";path=" + path : "") + ( (domain) ? ";domain=" + domain : "") + ( (secure) ? ";secure" : ""); document.cookie = cookieString; } ,debugmsg : function(text) { var area = document.getElementById("ddtree:debug"); if (area) area.value += new Date().getTime() + ": " + text + "\n"; } ,setMaximumDepth : function(maxDepth) { this.maximumDepth = maxDepth; } ,setMessageMaximumDepthReached : function(newMessage) { this.messageMaximumDepthReached = newMessage; } , setImageFolder : function(path) { this.imageFolder = path; } , setFolderImage : function(imagePath) { this.folderImage = imagePath; } , setLeafImage : function(imagePath) { this.leafImage = imagePath; } , setPlusImage : function(imagePath) { this.plusImage = imagePath; } , setAllowDrag : function(allow) { this.allowDrag = allow; } , setMinusImage : function(imagePath) { this.minusImage = imagePath; } , setTreeId : function(idOfTree) { this.idOfTree = idOfTree; this.floatingContainer.id = idOfTree + "-container"; } , setOnComplete : function(f) { this.onComplete = f; } , setOnError : function(f) { this.onError = f; } , setRequestUrl : function(url) { this.requestUrl = url; } , setRequestParameter : function(parameter) { this.requestParameter = parameter; } , setFieldId : function(id) { this.fieldId = id; } , setIncludeImage : function(include) { this.includeImage = include; } , setMovedClass : function(movedClass) { this.movedClass = movedClass; } , expandAll : function() { var menuItems = document.getElementById(this.idOfTree).getElementsByTagName('LI'); for(var no=0;no0 && subItems[0].style.display!='block'){ JSTreeObj.showHideNode(false,menuItems[no].id.replace(/[^-0-9]/g,'')); } } } , collapseAll : function() { var menuItems = document.getElementById(this.idOfTree).getElementsByTagName('LI'); for(var no=0;no0 && subItems[0].style.display=='block'){ JSTreeObj.showHideNode(false,menuItems[no].id.replace(/[^-0-9]/g,'')); } } } , /* Find top pos of a tree node */ getTopPos : function(obj){ var curtop = 0; if (obj.offsetParent) { while (obj.offsetParent) { curtop += obj.offsetTop obj = obj.offsetParent; } } else if (obj.y) curtop += obj.y; if (document.all) return curtop/1 + 13; else return curtop/1 + 13; } , /* Find left pos of a tree node */ getLeftPos : function(obj){ var curleft = 0; if (obj.offsetParent) { while (obj.offsetParent) { curleft += obj.offsetLeft obj = obj.offsetParent; } } else if (obj.x) curleft += obj.x; if (document.all) return curleft/1 - 2; else return curleft; } , showHideNode : function(e,inputId) { if(inputId){ if(!document.getElementById('dhtmlgoodies_treeNode'+inputId))return; thisNode = document.getElementById('dhtmlgoodies_treeNode'+inputId).getElementsByTagName('IMG')[0]; }else { thisNode = this; if(this.tagName != 'IMG')thisNode = this.parentNode.getElementsByTagName('IMG')[0]; } if(thisNode.style.visibility=='hidden')return; var parentNode = thisNode.parentNode; inputId = parentNode.id.replace(/[^-0-9]+/g,''); if(thisNode.src.indexOf(JSTreeObj.plusImage)>=0){ thisNode.src = thisNode.src.replace(JSTreeObj.plusImage,JSTreeObj.minusImage); var ul = parentNode.getElementsByTagName('UL')[0]; ul.style.display='block'; if(!initExpandedNodes)initExpandedNodes = ','; if(initExpandedNodes.indexOf(',' + inputId + ',')<0) initExpandedNodes = initExpandedNodes + inputId + ','; }else{ thisNode.src = thisNode.src.replace(JSTreeObj.minusImage,JSTreeObj.plusImage); parentNode.getElementsByTagName('UL')[0].style.display='none'; initExpandedNodes = initExpandedNodes.replace(',' + inputId,''); } JSTreeObj.Set_Cookie('dhtmlgoodies_expandedNodes_' + JSTreeObj.idOfTree, initExpandedNodes, 500); return false; } , /* Initialize drag */ initDrag : function(e) { JSTreeObj.debugmsg("initDrag"); if(document.all)e = event; var subs = JSTreeObj.floatingContainer.getElementsByTagName('LI'); if(subs.length>0){ if(JSTreeObj.dragNode_sourceNextSib){ JSTreeObj.dragNode_parent.insertBefore(JSTreeObj.dragNode_source,JSTreeObj.dragNode_sourceNextSib); }else{ JSTreeObj.dragNode_parent.appendChild(JSTreeObj.dragNode_source); } } JSTreeObj.dragNode_source = this.parentNode; JSTreeObj.dragNode_parent = this.parentNode.parentNode; JSTreeObj.dragNode_sourceNextSib = false; if(JSTreeObj.dragNode_source.nextSibling)JSTreeObj.dragNode_sourceNextSib = JSTreeObj.dragNode_source.nextSibling; JSTreeObj.dragNode_destination = false; JSTreeObj.dragDropTimer = 0; JSTreeObj.timerDrag(); return false; } , timerDrag : function() { if(this.dragDropTimer>=0 && this.dragDropTimer<10){ this.dragDropTimer = this.dragDropTimer + 1; setTimeout('JSTreeObj.timerDrag()',20); return; } if(this.dragDropTimer==10) { JSTreeObj.floatingContainer.style.display='block'; JSTreeObj.floatingContainer.appendChild(JSTreeObj.dragNode_source); } } , moveDragableNodes : function(e) { if(JSTreeObj.dragDropTimer<10)return; if(document.all)e = event; dragDrop_x = e.clientX/1 + 5 + document.body.scrollLeft; dragDrop_y = e.clientY/1 + 5 + document.documentElement.scrollTop; JSTreeObj.floatingContainer.style.left = dragDrop_x + 'px'; JSTreeObj.floatingContainer.style.top = dragDrop_y + 'px'; var thisObj = this; if (thisObj != document.documentElement) { while ((! thisObj.tagName) || (thisObj.tagName != 'LI')) { if (thisObj.parentNode) { thisObj = thisObj.parentNode; } else { break; } } } JSTreeObj.dragNode_noSiblings = false; var tmpVar = thisObj.getAttribute('noSiblings'); if(!tmpVar)tmpVar = thisObj.noSiblings; if(tmpVar=='true')JSTreeObj.dragNode_noSiblings=true; JSTreeObj.dragNode_noChildren = false; tmpVar = thisObj.getAttribute('noChildren'); if(!tmpVar)tmpVar = thisObj.noChildren; if(tmpVar=='true')JSTreeObj.dragNode_noChildren=true; if (JSTreeObj.dragNode_noSiblings && JSTreeObj.dragNode_noChildren) { return false; } if(thisObj && thisObj.id) { JSTreeObj.dragNode_destination = thisObj; var img = thisObj.getElementsByTagName('IMG')[1]; var tmpObj= JSTreeObj.dropTargetIndicator; tmpObj.style.display='block'; var eventSourceObj = this; if(JSTreeObj.dragNode_noSiblings && eventSourceObj.tagName=='IMG') { eventSourceObj = eventSourceObj.nextSibling; } if(JSTreeObj.dragNode_noChildren && eventSourceObj.tagName != 'IMG') { eventSourceObj = img; } var tmpImg = tmpObj.getElementsByTagName('IMG')[0]; if((this.tagName != 'IMG' || JSTreeObj.dragNode_noSiblings) && !JSTreeObj.dragNode_noChildren){ tmpImg.src = tmpImg.src.replace('ind1','ind2'); JSTreeObj.insertAsSub = true; tmpObj.style.left = (JSTreeObj.getLeftPos(eventSourceObj) + JSTreeObj.indicator_offsetX_sub) + 'px'; }else{ tmpImg.src = tmpImg.src.replace('ind2','ind1'); JSTreeObj.insertAsSub = false; tmpObj.style.left = (JSTreeObj.getLeftPos(eventSourceObj) + JSTreeObj.indicator_offsetX) + 'px'; } tmpObj.style.top = (JSTreeObj.getTopPos(thisObj) + JSTreeObj.indicator_offsetY) + 'px'; } return false; } , dropDragableNodes:function() { if(JSTreeObj.dragDropTimer<10){ JSTreeObj.dragDropTimer = -1; return; } var showMessage = false; if(JSTreeObj.dragNode_destination){ // Check depth var countUp = JSTreeObj.dragDropCountLevels(JSTreeObj.dragNode_destination,'up'); var countDown = JSTreeObj.dragDropCountLevels(JSTreeObj.dragNode_source,'down'); var countLevels = countUp/1 + countDown/1 + (JSTreeObj.insertAsSub?1:0); if(countLevels>JSTreeObj.maximumDepth){ JSTreeObj.dragNode_destination = false; showMessage = true; // Used later down in this function } } if(JSTreeObj.dragNode_destination){ if(JSTreeObj.insertAsSub){ var uls = JSTreeObj.dragNode_destination.getElementsByTagName('UL'); if(uls.length>0){ ul = uls[0]; ul.style.display='block'; var lis = ul.getElementsByTagName('LI'); if(lis.length>0){ // Sub elements exists - drop dragable node before the first one ul.insertBefore(JSTreeObj.dragNode_source,lis[0]); }else { // No sub exists - use the appendChild method - This line should not be executed unless there's something wrong in the HTML, i.e empty