/************************************************************************************************************ Drag and drop folder tree Copyright (C) 2006 DTHMLGoodies.com, Alf Magne Kalleland This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Dhtmlgoodies.com., hereby disclaims all copyright interest in this script written by Alf Magne Kalleland. Alf Magne Kalleland, 2006 Owner of DHTMLgoodies.com ************************************************************************************************************/ var JSTreeObj; var treeUlCounter = 0; var nodeId = 1; /* Constructor */ function JSDragDropTree() { var idOfTree; var imageFolder; var folderImage; var plusImage; var minusImage; var maximumDepth; var dragNode_source; var dragNode_parent; var dragNode_sourceNextSib; var dragNode_noSiblings; var ajaxObjects; var dragNode_destination; var floatingContainer; var dragDropTimer; var dropTargetIndicator; var insertAsSub; var indicator_offsetX; var indicator_offsetX_sub; var indicator_offsetY; this.imageFolder = 'images/'; this.folderImage = 'dhtmlgoodies_folder.gif'; this.plusImage = 'dhtmlgoodies_plus.gif'; this.minusImage = 'dhtmlgoodies_minus.gif'; this.maximumDepth = 6; var messageMaximumDepthReached; var filePathRenameItem; var filePathDeleteItem; var additionalRenameRequestParameters = {}; var additionalDeleteRequestParameters = {}; var renameAllowed; var deleteAllowed; var currentlyActiveItem; var contextMenu; var currentItemToEdit; // Reference to item currently being edited(example: renamed) var helpObj; this.contextMenu = false; 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; this.currentItemToEdit = 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.renameAllowed = true; this.deleteAllowed = true; this.currentlyActiveItem = false; this.filePathRenameItem = 'folderTree_updateItem.php'; this.filePathDeleteItem = 'folderTree_updateItem.php'; this.ajaxObjects = new Array(); this.helpObj = false; this.RENAME_STATE_BEGIN = 1; this.RENAME_STATE_CANCELED = 2; this.RENAME_STATE_REQUEST_SENDED = 3; this.renameState = null; } /* JSDragDropTree class */ JSDragDropTree.prototype = { // {{{ addEvent() /** * * This function adds an event listener to an element on the page. * * @param Object whichObject = Reference to HTML element(Which object to assigne the event) * @param String eventType = Which type of event, example "mousemove" or "mouseup" * @param functionName = Name of function to execute. * * @public */ addEvent : function(whichObject,eventType,functionName) { if(whichObject.attachEvent){ whichObject['e'+eventType+functionName] = functionName; whichObject[eventType+functionName] = function(){whichObject['e'+eventType+functionName]( window.event );} whichObject.attachEvent( 'on'+eventType, whichObject[eventType+functionName] ); } else whichObject.addEventListener(eventType,functionName,false); } // }}} , // {{{ removeEvent() /** * * This function removes an event listener from an element on the page. * * @param Object whichObject = Reference to HTML element(Which object to assigne the event) * @param String eventType = Which type of event, example "mousemove" or "mouseup" * @param functionName = Name of function to execute. * * @public */ removeEvent : function(whichObject,eventType,functionName) { if(whichObject.detachEvent){ whichObject.detachEvent('on'+eventType, whichObject[eventType+functionName]); whichObject[eventType+functionName] = null; } else whichObject.removeEventListener(eventType,functionName,false); } , 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; } , setFileNameRename : function(newFileName) { this.filePathRenameItem = newFileName; } , setFileNameDelete : function(newFileName) { this.filePathDeleteItem = newFileName; } , setAdditionalRenameRequestParameters : function(requestParameters) { this.additionalRenameRequestParameters = requestParameters; } , setAdditionalDeleteRequestParameters : function(requestParameters) { this.additionalDeleteRequestParameters = requestParameters; } ,setRenameAllowed : function(renameAllowed) { this.renameAllowed = renameAllowed; } , setDeleteAllowed : function(deleteAllowed) { this.deleteAllowed = deleteAllowed; } ,setMaximumDepth : function(maxDepth) { this.maximumDepth = maxDepth; } ,setMessageMaximumDepthReached : function(newMessage) { this.messageMaximumDepthReached = newMessage; } , setImageFolder : function(path) { this.imageFolder = path; } , setFolderImage : function(imagePath) { this.folderImage = imagePath; } , setPlusImage : function(imagePath) { this.plusImage = imagePath; } , setMinusImage : function(imagePath) { this.minusImage = imagePath; } , setTreeId : function(idOfTree) { this.idOfTree = idOfTree; } , 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); } } } , 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); } } } , /* Find top pos of a tree node */ getTopPos : function(obj){ var top = obj.offsetTop/1; while((obj = obj.offsetParent) != null){ if(obj.tagName!='HTML')top += obj.offsetTop; } if(document.all)top = top/1 + 13; else top = top/1 + 4; return top; } , /* Find left pos of a tree node */ getLeftPos : function(obj){ var left = obj.offsetLeft/1 + 1; while((obj = obj.offsetParent) != null){ if(obj.tagName!='HTML')left += obj.offsetLeft; } if(document.all)left = left/1 - 2; return left; } , showHideNode : function(e,inputId) { if(inputId){ if(!document.getElementById(inputId))return; thisNode = document.getElementById(inputId).getElementsByTagName('IMG')[0]; }else { thisNode = this; if(this.tagName=='A')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',initExpandedNodes,500); return false; } , /* Initialize drag */ initDrag : function(e) { 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.tagName=='A' || thisObj.tagName=='IMG')thisObj = thisObj.parentNode; JSTreeObj.dragNode_noSiblings = false; var tmpVar = thisObj.getAttribute('noSiblings'); if(!tmpVar)tmpVar = thisObj.noSiblings; if(tmpVar=='true')JSTreeObj.dragNode_noSiblings=true; 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; var tmpImg = tmpObj.getElementsByTagName('IMG')[0]; if(this.tagName=='A' || JSTreeObj.dragNode_noSiblings){ 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