Ajax Layer JavaScript DHTML



DragList - Javascript Drag and Drop Ordered Lists in Javascript


/**************************************************
 * dom-drag.js
 * 09.25.2001
 * www.youngpup.net
 **************************************************
 * 10.28.2001 - fixed minor bug where events
 * sometimes fired off the handle, not the root.
 **************************************************
 * 05.30.2005 - added a workaround for firefox
 * activating links when finished dragging.
 * mmosier@astrolabe.com
 **************************************************/
var Drag = {
  obj : null,
  init : function(o, oRoot, minX, maxX, minY, maxY, bSwapHorzRef, bSwapVertRef, fXMapper, fYMapper)
  {
    o.onmousedown  = Drag.start;
    o.hmode      = bSwapHorzRef ? false : true ;
    o.vmode      = bSwapVertRef ? false : true ;
    o.root = oRoot && oRoot != null ? oRoot : o ;
    if (o.hmode  && isNaN(parseInt(o.root.style.left  ))) o.root.style.left   = "0px";
    if (o.vmode  && isNaN(parseInt(o.root.style.top   ))) o.root.style.top    = "0px";
    if (!o.hmode && isNaN(parseInt(o.root.style.right ))) o.root.style.right  = "0px";
    if (!o.vmode && isNaN(parseInt(o.root.style.bottom))) o.root.style.bottom = "0px";
    o.minX  = typeof minX != 'undefined' ? minX : null;
    o.minY  = typeof minY != 'undefined' ? minY : null;
    o.maxX  = typeof maxX != 'undefined' ? maxX : null;
    o.maxY  = typeof maxY != 'undefined' ? maxY : null;
    o.xMapper = fXMapper ? fXMapper : null;
    o.yMapper = fYMapper ? fYMapper : null;
    o.root.onDragStart  = new Function();
    o.root.onDragEnd  = new Function();
    o.root.onDrag    = new Function();
  },
  start : function(e)
  {
    var o = Drag.obj = this;
    e = Drag.fixE(e);
    var y = parseInt(o.vmode ? o.root.style.top  : o.root.style.bottom);
    var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right );
    o.root.onDragStart(x, y);
    o.startX    = x;
    o.startY    = y;
    o.lastMouseX  = e.clientX;
    o.lastMouseY  = e.clientY;
    if (o.hmode) {
      if (o.minX != null)  o.minMouseX  = e.clientX - x + o.minX;
      if (o.maxX != null)  o.maxMouseX  = o.minMouseX + o.maxX - o.minX;
    } else {
      if (o.minX != null) o.maxMouseX = -o.minX + e.clientX + x;
      if (o.maxX != null) o.minMouseX = -o.maxX + e.clientX + x;
    }
    if (o.vmode) {
      if (o.minY != null)  o.minMouseY  = e.clientY - y + o.minY;
      if (o.maxY != null)  o.maxMouseY  = o.minMouseY + o.maxY - o.minY;
    } else {
      if (o.minY != null) o.maxMouseY = -o.minY + e.clientY + y;
      if (o.maxY != null) o.minMouseY = -o.maxY + e.clientY + y;
    }
    document.onmousemove  = Drag.drag;
    document.onmouseup    = Drag.end;
    if (o.linkDisabled) {
      var hrefs = o.root.getElementsByTagName("a");
      for (var i = 0; i < hrefs.length; i++) {
        hrefs[i].onclick = hrefs[i].prevOnclick;
        hrefs[i].prevOnclick = null;
      }
      o.linkDisabled = false;
    }
    return false;
  },
  drag : function(e)
  {
    e = Drag.fixE(e);
    var o = Drag.obj;
    var ey  = e.clientY;
    var ex  = e.clientX;
    var y = parseInt(o.vmode ? o.root.style.top  : o.root.style.bottom);
    var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right );
    var nx, ny;
    if (o.minX != null) ex = o.hmode ? Math.max(ex, o.minMouseX) : Math.min(ex, o.maxMouseX);
    if (o.maxX != null) ex = o.hmode ? Math.min(ex, o.maxMouseX) : Math.max(ex, o.minMouseX);
    if (o.minY != null) ey = o.vmode ? Math.max(ey, o.minMouseY) : Math.min(ey, o.maxMouseY);
    if (o.maxY != null) ey = o.vmode ? Math.min(ey, o.maxMouseY) : Math.max(ey, o.minMouseY);
    nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1));
    ny = y + ((ey - o.lastMouseY) * (o.vmode ? 1 : -1));
    if (o.xMapper)    nx = o.xMapper(y)
    else if (o.yMapper)  ny = o.yMapper(x)
    Drag.obj.root.style[o.hmode ? "left" : "right"] = nx + "px";
    Drag.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px";
    Drag.obj.lastMouseX  = ex;
    Drag.obj.lastMouseY  = ey;
    var threshold = 4;
    if (!o.linkDisabled) {
      if (Math.abs(nx - o.startX) > threshold || Math.abs(ny - o.startY) > threshold) {
        var hrefs = o.root.getElementsByTagName("a");
        for (var i = 0; i < hrefs.length; i++) {
          hrefs[i].prevOnclick = hrefs[i].onclick;
          hrefs[i].onclick = function() { return false; };
        }
        o.linkDisabled = true;
      }
    }
    Drag.obj.root.onDrag(nx, ny, Drag.obj.root);
    return false;
  },
  end : function()
  {
    document.onmousemove = null;
    document.onmouseup   = null;
    Drag.obj.root.onDragEnd(  parseInt(Drag.obj.root.style[Drag.obj.hmode ? "left" : "right"]), 
                  parseInt(Drag.obj.root.style[Drag.obj.vmode
                                    ? "top" : "bottom"]), Drag.obj.root);
    Drag.obj = null;
  },
  fixE : function(e)
  {
    if (typeof e == 'undefined') e = window.event;
    if (typeof e.layerX == 'undefined') e.layerX = e.offsetX;
    if (typeof e.layerY == 'undefined') e.layerY = e.offsetY;
    return e;
  }
};



// ----------------------------------------------------------------------------
// (c) Copyright, DTLink, LLC 1997-2005
//     http://www.dtlink.com
//
// DragList - Drag and Drop Ordered Lists
//
// Javascript Support file for formVista  fvml tag.
//
// For more information please see:
//
//    http://www.formvista.com/otherprojects/draglist.html
//
// For questions or comments please contact us at:
//
//     http://www.formvista.com/contact.html
//
// LICENSE: This file is governed by the new BSD license. For more information
// please see the LICENSE.txt file accompanying this package. 
//
// REVISION HISTORY:
//
// 2004-11-12 YmL:
//  .  initial revision.
//
// 2005-05-28 YmL:
//  .  pulled out of formVista, relicensed and packaged as a standalone implementation.
//
// 2005-06-02 mtmosier:
//  .  added horizontal dragging support.
//
// ------------------------
/**
* constructor for dragList class
*/
function fv_dragList( name )
  {
  // name of this dragList. Must match the id of the root DIV tag.
  this.dragListRootId = name;
  // array of item offsets
  this.offsetsX = new Array();
  this.offsetsY = new Array();
  }
// ----------------------------------------------
/**
* setup the draglist prior to use
*
* @param string orientation defaults to vert. if set to "horz" renders horizontally.
* @param string itemTagName. if null defaults to "div". Can be "span".
*/
fv_dragList.prototype.setup = function( orientation, itemTagName )
  {
  var horizontal;
  if ( orientation == "horz" )
    horizontal = true;
  else
    horizontal = false;
  this.listRoot = document.getElementById( this.dragListRootId );
  this.listItems = this.getListItems( itemTagName );
  for (var i = 0; i < this.listItems.length; i++) 
    {
    if ( this.listItems[i] == undefined )
      continue;
    if ( horizontal )
      {
      Drag.init(this.listItems[i], null, null, null, 0, 0);
      }
    else
      {
      Drag.init(this.listItems[i], null, 0, 0, null, null);
      }
    // ---------------------------------------------------
    // on drag method
    this.listItems[i].onDrag = function( x, y, thisElem ) 
      {
      x = thisElem.offsetLeft;
      y = thisElem.offsetTop;
      // this is a callback from the dom-drag code. From within this
      // function "this" does not refer to the fv_draglist function.
      draglist = getDragList( thisElem );
      draglist.recalcOffsets( itemTagName );
      var pos = draglist.getCurrentOffset( thisElem, itemTagName );
      //var listItems = this.getListItems( itemTagName );
      // if bottom edge is below top of lower item.
      var testMoveUp;
      var testMoveDown;
      if ( horizontal )
        {
        testMoveUp = (x + draglist.getDivWidth(thisElem) > draglist.offsetsX[pos + 1] + draglist.getDivWidth( draglist.listItems[pos + 1] ));
        testMoveDown = x < draglist.offsetsX[pos - 1];
        }
      else
        {
        testMoveUp = (y + draglist.getDivHeight(thisElem) > draglist.offsetsY[pos + 1] + draglist.getDivHeight( draglist.listItems[pos + 1] ));
        testMoveDown = y < draglist.offsetsY[pos - 1];
        }
      if (( pos != draglist.listItems.length - 1) && testMoveUp )
        { 
        draglist.listRoot.removeChild(thisElem);
        if ( pos + 1 == draglist.listItems.length )
          {
          draglist.listRoot.appendChild( thisElem );
          }
        else
          {
          draglist.listRoot.insertBefore(thisElem, draglist.listItems[pos+1]);
          }
        thisElem.style["top"] = "0px";
        thisElem.style["left"] = "0px";
        }
      else if ( pos != 0 && testMoveDown ) 
        { 
        draglist.listRoot.removeChild(thisElem);
        draglist.listRoot.insertBefore(thisElem, draglist.listItems[pos-1]);
        thisElem.style["top"] = "0px";
        thisElem.style["left"] = "0px";
        }
      };
    this.listItems[i].onDragEnd = function(x,y,thisElem) 
      {
      thisElem.style["top"] = "0px";
      thisElem.style["left"] = "0px";
      }
    }  // end of for loop.
  this.recalcOffsets( itemTagName );
  }  // end of setup.
// ----------------------------------------------
/**
* update the order value fields and submit the form.
*/
fv_dragList.prototype.do_submit = function( formName, dragListRootId )
  {
  var listOrderItems = this.listRoot.getElementsByTagName("input");
  for (var i = 0; i < listOrderItems.length; i++) 
    {
    listOrderItems[i].value = i;
    }
  expr = "document." + formName + ".submit()";
  eval( expr );
  }
// ----------------------------------------------
// "Private" methods.
// ----------------------------------------------
fv_dragList.prototype.recalcOffsets = function( itemTagName ) 
  {
  var listItems = this.getListItems( itemTagName );
  for (var i = 0; i < listItems.length; i++) 
    {
    this.offsetsX[i] = listItems[i].offsetLeft;
    this.offsetsY[i] = listItems[i].offsetTop;
    }
  }
fv_dragList.prototype.getCurrentOffset = function(elem, itemTagName) 
  { 
  var listItems = this.getListItems( itemTagName );
  for (var i = 0; i < listItems.length; i++) 
    {
    if (listItems[i] == elem) 
      { 
      return i;
      }
    }
  }
fv_dragList.prototype.getDivWidth = function(elem)                   
  {
  if (( elem == undefined) || ( elem.offsetWidth == undefined ))
    return( 0 );
  value = elem.offsetWidth;
  if (isNaN(value))
    {
    value = 0;
    }
  return( value );
  }
fv_dragList.prototype.getDivHeight = function(elem) 
  {
  if (( elem == undefined) || ( elem.offsetHeight == undefined ))
    return( 0 );
  value = elem.offsetHeight;
  if (isNaN(value))
    {
    value = 25;
    }
  return( value );
  }
/**
* return list of draggable items
*/
fv_dragList.prototype.getListItems = function( itemTagName )
  {
  if ( itemTagName == undefined )
    {
    itemTagName = "div";
    }
  var listItems = this.listRoot.getElementsByTagName( itemTagName );
  return( listItems );
  }
// end of draglist class definition.
// -------------------------------------
/**
* add a new dragList to the list of draglists on this page
*
* This implementatoin supports multiple managed draglists on
* a single page. The index is contained in a global dragListIndex
* array that must be declared in the page.
*/
function addDragList( draglist )
  {
  dragListIndex[ draglist.dragListRootId ] = draglist;
  }
// -------------------------------------------------------
/**
* given a draggable div element, return the draglist it belongs to
*
* @see fv_draglist.prototype.setup
* @todo this should probably be a method inside the draglist class.
*/
function getDragList( elem )
  {
  // given a list item return the drag list it belongs to.
  var draglistContainer = elem.parentNode;
  var draglist = dragListIndex[ draglistContainer.id ];
  return( draglist );
  }
// END







draglist - Drag and Drop Ordered Lists in Javascript





This is a demonstration of the draglist Drag and Drop Ordered list implementation used
in the formVista business component framework 
by DTLink Software.



You can grab the (drag) text and reorder the items on the list. On pressing submit,
the new order of the items will be sent to the server and displayed.



draglists are enclosed in a wrapping <DIV> tag. Each item in the list
is contained in a draggable div or span. When submit is pressed the list of items is 
queried and the position values are modified. 



For more information see the Drag List home page.





















Vertical Dragging Example
















The items below are draggable.
  
    
  








  
    
       
          
            
            
            
            

                          (Drag 1)

// If these items were coming from a database, we would use the offset in 
// the draglist_items array to hold the unique key of the item. We make use 
// of the fact that PHP arrays do not have sequential keys to do this.
//
// The value here is the items initial position. the draglist.do_submit() function
// updates these values onSubmit. 
?>












                          (Drag 2)













                          (Drag 3)













                          (Drag 4)













                          (Drag 5)













                          (Drag 6)







  
    
  


onClick="javascript:draglist_manager.do_submit('draglist_form','draglist_container')">








































Horizontal Example















The items below are draggable.
  
    
  



// Notice that this div has a distinct name from the other
// draggable container div.
?>

  
    
  
  
  
    
  
  
  
    
  
  
  
    
  
  
  
    
  
  
  
    
  
  



  
    
  

// do_submit() queries the new order of the items in the list and 
// updates the hidden values.
?>


























Logos for AnswerTool, NeoPhoto, PersonalStockStreamer and formVista are trademarks of DTLink, LLC.




Back to Drag List Page








// a bit ugly. draglist.js assumes the existence of a global
// dragListIndex array.
var dragListIndex = new Array();
// manager classes. 
draglist_manager = new fv_dragList( 'draglist_container' );
draglist_manager_horz = new fv_dragList( 'draglist_container_horz' );
// queries all top level  under the draglist_container
// div and sets up dragging.
draglist_manager.setup();
// queries all top level 's under the draglist_container_horz
// div and sets up horizontal dragging.
draglist_manager_horz.setup( "horz", "span");
// addes the newly created dragList to the list of draglists on 
// the page (i.e. we can have more than one on a page)
addDragList( draglist_manager );
addDragList( draglist_manager_horz );







Copyright  1997 - 2005 DTLink Software