JavaScript DHTML/Ajax Layer/Panel

Материал из Web эксперт
Перейти к: навигация, поиск

Rounded Corners

<A href="http://www.wbex.ru/Code/JavaScriptDownload/MochiKit-1.3.1.zip">MochiKit-1.3.1.zip( 302 k)</a>

1. <A href="/Code/JavaScript/Ajax-Layer/Simpledraganddroppanel.htm">Simple drag and drop panel</a> <A href="/Code/JavaScript/Ajax-Layer/Simpledraganddroppanel.htm"></a> 2. <A href="/Code/JavaScript/Ajax-Layer/ViewPaneandLoadPanel.htm">View Pane and Load Panel</a> <A href="/Code/JavaScript/Ajax-Layer/ViewPaneandLoadPanel.htm"></a> 3. <A href="/Code/JavaScript/Ajax-Layer/ViewPaneandExplorer.htm">ViewPane and Explorer</a> <A href="/Code/JavaScript/Ajax-Layer/ViewPaneandExplorer.htm"></a>

Simple drag and drop panel

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>js-graph.it homepage</title>
<script type="text/javascript">
/*********************
 * browser detection *
 *********************/
var ie=document.all;
var nn6=document.getElementById&&!document.all;
/*****************
 * drag and drop *
 *****************/
 
var isdrag=false;
var mouseStartX, mouseStartY;    // mouse position when drag starts
var elementStartX, elementStartY;  // element position when drag starts
var elementToMove;
var blockToMove;
// an array containing bounds to be respected while dragging elements,
// these bounds are left, top, left + width, top + height of the parent element.
var bounds = new Array(4);
function movemouse(e)
{
  if (isdrag)
  {
    var currentMouseX = nn6 ? e.clientX : event.clientX;
    var currentMouseY = nn6 ? e.clientY : event.clientY;
    var newElementX = elementStartX + currentMouseX - mouseStartX;
    var newElementY = elementStartY + currentMouseY - mouseStartY;
    // check bounds
    // note: the "-1" and "+1" is to avoid borders overlap
    if(newElementX < bounds[0])
      newElementX = bounds[0] + 1;
    if(newElementX + elementToMove.offsetWidth > bounds[2])
      newElementX = bounds[2] - elementToMove.offsetWidth - 1;
    if(newElementY < bounds[1])
      newElementY = bounds[1] + 1;
    if(newElementY + elementToMove.offsetHeight > bounds[3])
      newElementY = bounds[3] - elementToMove.offsetHeight - 1;
    
    // move element
    elementToMove.style.left = newElementX + "px";
    elementToMove.style.top  = newElementY + "px";
//    elementToMove.style.left = newElementX / elementToMove.parentNode.offsetWidth * 100 + "%";
//    elementToMove.style.top  = newElementY / elementToMove.parentNode.offsetHeight * 100 + "%";
  
    elementToMove.style.right = null;
    elementToMove.style.bottom = null;
    
    if(blockToMove)
      blockToMove.onMove();
    return false;
  }
}
/**
 * finds the innermost draggable element starting from the one that generated the event "e"
 * (i.e.: the html element under mouse pointer), then setup the document"s onmousemove function to
 * move the element around.
 */
function selectmouse(e) 
{
  
  var eventSource = nn6 ? e.target : event.srcElement;
  
  while (eventSource != document.body && !hasClass(eventSource, "draggable"))
  {    
    eventSource = nn6 ? eventSource.parentNode : eventSource.parentElement;
  }
  // if a draggable element was found, calculate its actual position
  if (hasClass(eventSource, "draggable"))
  {
    isdrag = true;
    elementToMove = eventSource;
    
    // calculate start point
    //elementStartX = calculateOffsetLeft(elementToMove);
    //elementStartY = calculateOffsetTop(elementToMove);
    elementStartX = elementToMove.offsetLeft;
    elementStartY = elementToMove.offsetTop;
    
    // calculate mouse start point
    mouseStartX = nn6 ? e.clientX : event.clientX;
    mouseStartY = nn6 ? e.clientY : event.clientY;
    
    // calculate bounds as left, top, width, height of the parent element
    if(elementToMove.parentNode.style.position == "absolute")
    {
      bounds[0] = 0;
      bounds[1] = 0;
    }
    else
    {
      bounds[0] = calculateOffsetLeft(elementToMove.parentNode);
      bounds[1] = calculateOffsetTop(elementToMove.parentNode);
    }
    bounds[2] = bounds[0] + elementToMove.parentNode.offsetWidth;
    bounds[3] = bounds[1] + elementToMove.parentNode.offsetHeight;
    
    
    // either find the block related to the dragging element to call its onMove method
    blockToMove = findBlock(eventSource.id);
    document.onmousemove = movemouse;
    
    return false;
  }
}
document.onmousedown=selectmouse;
document.onmouseup=new Function("isdrag=false");

/*************
 * Constants *
 *************/
var AUTO = 0;
var HORIZONTAL = 1;
var VERTICAL = 2;
/**************
 * Inspectors *
 **************/
var inspectors = new Array();
/**
 * The canvas class.
 * This class is built on a div html element.
 */
function Canvas(htmlElement)
{
  /*
   * initialization
   */
  this.id = htmlElement.id;
  this.htmlElement = htmlElement;
  this.blocks = new Array();
  this.connectors = new Array();
  
  this.initCanvas = function()
  {
    // inspect canvas children to identify first level blocks
    this.findNestedBlocksAndConnectors(this.htmlElement);
    
    // init connectors
    var i;
    for(i = 0; i < this.connectors.length; i++)
    {
      this.connectors[i].initConnector();
    }
  }
  
  this.findNestedBlocksAndConnectors = function(node)
  {
    var children = node.childNodes;
    var i;
    var offsetLeft = calculateOffsetLeft(this.htmlElement);
    var offsetTop = calculateOffsetTop(this.htmlElement);
    
    for(i = 0; i < children.length; i++)
    {
      // move element in a "correct relative" position and set it size as fixed
      if(getStyle(children[i], "position") == "absolute")
      {
        children[i].style.left = children[i].offsetLeft + offsetLeft + "px";
        children[i].style.top = children[i].offsetTop + offsetTop + "px";
        children[i].style.width = children[i].offsetWidth;
        children[i].style.height = children[i].offsetHeight;
      }
    
      if(isBlock(children[i]))
      {
        // block found initialize it
        var newBlock = new Block(children[i], this);
        newBlock.initBlock();
        this.blocks.push(newBlock);
      }
      else if(isConnector(children[i]))
      {
        // connector found, just create it, source or destination blocks may not 
        // have been initialized yet
        var newConnector = new Connector(children[i], this);
        this.connectors.push(newConnector);
      }
      else
      {
        // continue searching nested elements
        this.findNestedBlocksAndConnectors(children[i]);
      }
    }    
  }
  
  /*
   * methods
   */  
  this.print = function()
  {
    var output = "<ul><legend>canvas: " + this.id + "</legend>";
    var i;
    for(i = 0; i < this.blocks.length; i++)
    {
      output += "<li>";
      output += this.blocks[i].print();
      output += "</li>";
    }
    output += "</ul>";
    return output;
  }
  
  /*
   * This function searches for a nested block with a given id
   */
  this.findBlock = function(blockId)
  {
    var result;
    var i;
    for(i = 0; i < this.blocks.length && !result; i++)
    {
      result = this.blocks[i].findBlock(blockId);
    }
    
    return result;
  }
  
  this.toString = function()
  {
    return "canvas: " + this.id;
  }
}
/*
 * Block class
 */
function Block(htmlElement, canvas)
{  
  /*
   * initialization
   */
   
  this.canvas = canvas;
  this.htmlElement = htmlElement;
  this.id = htmlElement.id;
  this.blocks = new Array();
  this.moveListeners = new Array();  
  
  
  this.initBlock = function()
  {
    // inspect block children to identify nested blocks
    var children = this.htmlElement.childNodes;
    var i;    
    for(i = 0; i < children.length; i++)
    {
      if(isBlock(children[i]))
      {
        var innerBlock = new Block(children[i], this.canvas);
        innerBlock.initBlock();
        this.blocks.push(innerBlock);
        this.moveListeners.push(innerBlock);
      }
    }
    
    //this.htmlElement.onmousemove = new Function("if(isdrag) findBlock(\"" + this.id + "\").onMove();");
  }
  
  this.top = function()
  {
    return calculateOffsetTop(this.htmlElement);
  }
  
  this.left = function()
  {
    return calculateOffsetLeft(this.htmlElement);
  }
  
  this.width = function()
  {
    return this.htmlElement.offsetWidth;
  }
  
  this.height = function()
  {
    return this.htmlElement.offsetHeight;
  }
  
  /*
   * methods
   */  
  this.print = function()
  {
    var output = "block: " + this.id;
    if(this.blocks.length > 0)
    {
      output += "<ul>";
      var i;
      for(i = 0; i < this.blocks.length; i++)
      {
        output += "<li>";
        output += this.blocks[i].print();
        output += "</li>";
      }
      output += "</ul>";
    }
    return output;
  }
  
  /*
   * This function searches for a nested block (or the block itself) with a given id
   */
  this.findBlock = function(blockId)
  {
    if(this.id == blockId)
      return this;
      
    var result;
    var i;
    for(i = 0; i < this.blocks.length && !result; i++)
    {
      result = this.blocks[i].findBlock(blockId);
    }
    
    return result;
  }
  
  this.move = function(left, top)
  {    
    this.htmlElement.style.left = left;
    this.htmlElement.style.top = top;
    this.onMove();
  }
    
  this.onMove = function()
  {
    var i;
    
    // notify listeners
    for(i = 0; i < this.moveListeners.length; i++)
    {
      this.moveListeners[i].onMove();
    }
  }
  
  this.toString = function()
  {
    return "block: " + this.id;
  }
}
/*
 * Connector class.
 * The init function takes two Block objects as arguments representing 
 * the source and destination of the connector
 */
function Connector(htmlElement, canvas)
{
  this.htmlElement = htmlElement;
  this.canvas = canvas;
  this.source = null;
  this.destination = null;
  this.startX = null;
  this.startY = null;
  this.destX = null;
  this.destY = null;
  this.segment1 = null;
  this.segment2 = null;
  this.segment3 = null;
  this.preferredOrientation = AUTO;
  this.orientation = HORIZONTAL;
  this.size = 1;
  this.color = "black";
  this.moveListeners = new Array();
  
  this.initConnector = function()
  {
    // detect the connector id
    if(this.htmlElement.id)
      this.id = this.htmlElement.id;
    else
      this.id = this.htmlElement.className;
      
    // split the class name to get the ids of the source and destination blocks
    var splitted = htmlElement.className.split(" ");
    if(splitted.length < 3)
    {
      alert("Unable to create connector \"" + id + "\", class is not in the correct format: connector <sourceBlockId>, <destBlockId>");
      return;
    }
    
    var connectorClass = splitted[0] + " " + splitted[1] + " " + splitted[2];
    
    this.source = this.canvas.findBlock(splitted[1]);
    if(!this.source)
    {
      alert("cannot find source block with id \"" + splitted[1] + "\"");
      return;
    }
    
    this.destination = this.canvas.findBlock(splitted[2]);
    if(!this.destination)
    {
      alert("cannot find destination block with id \"" + splitted[2] + "\"");
      return;
    }
    
    // check preferred orientation
    if(hasClass(this.htmlElement, "vertical"))
      this.preferredOrientation = VERTICAL;
    else if(hasClass(this.htmlElement, "horizontal"))
      this.preferredOrientation = HORIZONTAL;
    else
      this.preferredOrientation = AUTO;
    
    // build the segments
    this.segment1 = document.createElement("div");
    this.segment1.id = this.id + "_1";    
    this.canvas.htmlElement.appendChild(this.segment1);
    this.segment1.style.position = "absolute";
    this.segment1.style.overflow = "hidden";
    
    if(!getStyle(this.segment1, "background-color"))
      this.segment1.style.backgroundColor = this.color;
    this.segment1.className = connectorClass;
    
    this.segment2 = document.createElement("div");
    this.segment2.id = this.id + "_2";
    this.canvas.htmlElement.appendChild(this.segment2);
    this.segment2.className = connectorClass;    
    this.segment2.style.position = "absolute";
    this.segment2.style.overflow = "hidden";
    
    if(!getStyle(this.segment2, "background-color"))
      this.segment2.style.backgroundColor = this.color;
    
    this.segment3 = document.createElement("div");
    this.segment3.id = this.id + "_3";
    this.canvas.htmlElement.appendChild(this.segment3);
    this.segment3.style.position = "absolute";
    this.segment3.style.overflow = "hidden";
    
    if(!getStyle(this.segment3, "background-color"))
      this.segment3.style.backgroundColor = this.color;      
    this.segment3.className = connectorClass;
    
    this.repaint();
    
    this.source.moveListeners.push(this);
    this.destination.moveListeners.push(this);
    
    // call inspectors for this connector
    var i;
    for(i = 0; i < inspectors.length; i++)
    {
      inspectors[i].inspect(this);
    }
    
    // remove old html element
    this.htmlElement.parentNode.removeChild(this.htmlElement);
  }
  
  /**
   * Repaints the connector
   */
  this.repaint = function()
  {
    var sourceLeft = this.source.left();
    var sourceTop = this.source.top();
    var sourceWidth = this.source.width();
    var sourceHeight = this.source.height();
    
    var destinationLeft = this.destination.left();
    var destinationTop = this.destination.top();
    var destinationWidth = this.destination.width();
    var destinationHeight = this.destination.height();
    
    if(this.preferredOrientation == HORIZONTAL)
    {
      // use horizontal orientation except if it is impossible
      if((destinationLeft - sourceLeft - sourceWidth) *
        (sourceLeft - destinationLeft - destinationWidth) > 0)
        this.orientation = VERTICAL;
      else
        this.orientation = HORIZONTAL;
    }
    else if(this.preferredOrientation == VERTICAL)
    {
      // use vertical orientation except if it is impossible
      if((destinationTop - sourceTop - sourceHeight) *
        (sourceTop - destinationTop - destinationHeight) > 0)
        this.orientation = HORIZONTAL;
      else
        this.orientation = VERTICAL;
    }
    else
    {
      // auto orientation: change current orientation if it is impossible to maintain
      if(this.orientation == HORIZONTAL &&
        (destinationLeft - sourceLeft - sourceWidth) *
        (sourceLeft - destinationLeft - destinationWidth) > 0)
      {
        this.orientation = VERTICAL;
      }
      else if(this.orientation == VERTICAL &&
        (destinationTop - sourceTop - sourceHeight) *
        (sourceTop - destinationTop - destinationHeight) > 0)
      {
        this.orientation = HORIZONTAL;
      }
    }
    
    if(this.orientation == HORIZONTAL)
    {
      // deduce which face to use on source and destination blocks
      if(sourceLeft + sourceWidth / 2 < destinationLeft + destinationWidth / 2)
      {
        // use left side of the source block and right side of the destination block
        this.startX = sourceLeft + sourceWidth;
        this.destX = destinationLeft;
      }
      else
      {
        // use right side of the source block and left side of the destination block
        this.startX = sourceLeft;
        this.destX = destinationLeft + destinationWidth;
      }
      this.startY = sourceTop + sourceHeight / 2;
      this.destY = destinationTop + destinationHeight /2;
      
      // first horizontal segment positioning
      this.segment1.style.left = Math.min(this.startX, (this.destX + this.startX) / 2) + "px";
      this.segment1.style.top = this.startY + "px";
      this.segment1.style.width = Math.abs((this.startX - this.destX) / 2) + this.size + "px";
      this.segment1.style.height = this.size + "px";
      
      // vertical segment positioning
      this.segment2.style.left = ((this.startX + this.destX) /2) + "px";
      this.segment2.style.top = Math.min(this.startY, this.destY) + "px";
      this.segment2.style.width = this.size + "px";
      this.segment2.style.height = Math.abs(this.destY - this.startY) + "px";
      
      // second horizontal segment positioning
      this.segment3.style.left = Math.min((this.startX + this.destX) /2, this.destX) + "px";
      this.segment3.style.top = this.destY + "px";
      this.segment3.style.width = Math.abs((this.destX - this.startX) / 2) + "px";
      this.segment3.style.height = this.size + "px";
      
      // label positioning
      //this.htmlElement.style.left = this.startX + "px";
      //this.htmlElement.style.top = this.startY + this.size + "px";
    }
    else
    {
      // deduce which face to use on source and destination blocks
      if(sourceTop + sourceHeight / 2 < destinationTop + destinationHeight / 2)
      {
        // use bottom side of the sheightblock and top side of thtopestination block
        this.startY = sourceTop + sourceHeight;
        this.destY = destinationTop;
      }
      else
      {
        // use top side of the source block and bottom side of the destination block
        this.startY = sourceTop;
        this.destY = destinationTop + destinationHeight;
      }
      
      this.startX = sourceLeft + sourceWidth / 2;
      this.destX = destinationLeft + destinationWidth / 2;
      
      // first vertical segment positioning
      this.segment1.style.left = this.startX + "px";
      this.segment1.style.top = Math.min(this.startY, (this.destY + this.startY)/2) + "px";
      this.segment1.style.width = this.size + "px";
      this.segment1.style.height = Math.abs((this.startY - this.destY) / 2) + this.size + "px";
      
      // horizontal segment positioning
      this.segment2.style.left = Math.min(this.startX, this.destX) + "px";
      this.segment2.style.top = ((this.startY + this.destY) /2) + "px";
      this.segment2.style.width = Math.abs(this.destX - this.startX) + "px";
      this.segment2.style.height = this.size + "px";
      
      // second vertical segment positioning
      this.segment3.style.left = this.destX + "px";
      this.segment3.style.top = Math.min(this.destY, (this.destY + this.startY) / 2) + "px";
      this.segment3.style.width = this.size + "px";
      this.segment3.style.height = Math.abs((this.destY - this.startY) / 2) + "px";
      
      // label positioning
      //this.htmlElement.style.left = this.startX + "px";
      //this.htmlElement.style.top = this.startY + this.size + "px";
    }
  }
  
  this.onMove = function()
  {
    this.repaint();
    
    // notify listeners
    var i;
    for(i = 0; i < this.moveListeners.length; i++)
      this.moveListeners[i].onMove();
  }
}
function ConnectorEnd(connector, htmlElement, segment)
{
  this.connector = connector;
  this.htmlElement = htmlElement;
  this.connector.segment1.parentNode.appendChild(htmlElement);
  // strip extension
  this.src = this.htmlElement.src.substring(0, this.htmlElement.src.lastIndexOf("."));
  this.srcExtension = this.htmlElement.src.substring(this.htmlElement.src.lastIndexOf("."));
  
  this.orientation;
  
  this.repaint = function()
  {
    this.htmlElement.style.position = "absolute";
    
    var orientation;
    var left;
    var top;
    
    if(connector.orientation == HORIZONTAL)
    {
      left = segment.offsetLeft;
      orientation = "l";
      if(segment.offsetLeft == connector.segment2.offsetLeft)
      {
        left += segment.offsetWidth - this.htmlElement.offsetWidth;
        var orientation = "r";
      }
  
      top = segment.offsetTop - (this.htmlElement.offsetHeight / 2);
    }
    else
    {
      top = segment.offsetTop;
      orientation = "u";
      if(segment.offsetTop == connector.segment2.offsetTop)
      {
        top += segment.offsetHeight - this.htmlElement.offsetHeight;
        var orientation = "d";
      }
  
      left = segment.offsetLeft - (this.htmlElement.offsetWidth / 2);
    }
    
    this.htmlElement.style.left = Math.ceil(left) + "px";
    this.htmlElement.style.top = Math.ceil(top) + "px";
    
    if(this.htmlElement.tagName.toLowerCase() == "img" && this.orientation != orientation)
    {        
      this.htmlElement.src = this.src + "_" + orientation + this.srcExtension;
    }
    this.orientation = orientation;
  }
  
  this.onMove = function()
  {
    this.repaint();
  }
}
function SideConnectorLabel(connector, htmlElement, side)
{
  this.connector = connector;
  this.htmlElement = htmlElement;
  this.connector.segment1.parentNode.appendChild(htmlElement);
  if(side == "source")
    this.segment = connector.segment1;
  else
    this.segment = connector.segment3;
  this.side = side;
    
  this.repaint = function()
  {
    this.htmlElement.style.position = "absolute";
    
    var segmentOrientation;
    if(this.segment.offsetWidth < this.segment.offsetHeight)
      segmentOrientation = VERTICAL;
    else
      segmentOrientation = HORIZONTAL;
      
    var left = this.segment.offsetLeft;
    var top = this.segment.offsetTop;
    if(segmentOrientation == VERTICAL)
    {
      if(this.segment.offsetTop == connector.segment2.offsetTop)
      {
        // put label on the bottom of the connector (segment goes downward)
        top += this.segment.offsetHeight - this.htmlElement.offsetHeight;
      }
    }
    else
    {
      if(this.segment.offsetLeft == connector.segment2.offsetLeft)
      {
        // anchor the label on its right side to avoid overlap with the block
        left += this.segment.offsetWidth - this.htmlElement.offsetWidth;
      }
      if(this.segment.offsetTop < (this.side == "source" ? connector.segment3.offsetTop : connector.segment1.offsetTop))
      {
        // put label over the connector rather than below
        top -= this.htmlElement.offsetHeight;
      }      
    }
    
    this.htmlElement.style.left = Math.ceil(left) + "px";
    this.htmlElement.style.top = Math.ceil(top) + "px";
  }
  
  this.onMove = function()
  {
    this.repaint();
  }
}
function MiddleConnectorLabel(connector, htmlElement)
{
  this.connector = connector;
  this.htmlElement = htmlElement;
  this.connector.segment2.parentNode.appendChild(htmlElement);
  
  this.repaint = function()
  {
    this.htmlElement.style.position = "absolute";
    
    var segmentOrientation;
    if(connector.segment2.offsetWidth < connector.segment2.offsetHeight)
      segmentOrientation = VERTICAL;
    else
      segmentOrientation = HORIZONTAL;
      
    var left;
    var top;
    if(segmentOrientation == VERTICAL)
    {
      // put label at middle height on right side of the connector
      top = connector.segment2.offsetTop + (connector.segment2.offsetHeight - this.htmlElement.offsetHeight) / 2;
      left = connector.segment2.offsetLeft;
    }
    else
    {
      // put connector below the connector at middle widths
      top = connector.segment2.offsetTop;
      left = connector.segment2.offsetLeft + (connector.segment2.offsetWidth - this.htmlElement.offsetWidth) / 2;;
    }
    
    this.htmlElement.style.left = Math.ceil(left) + "px";
    this.htmlElement.style.top = Math.ceil(top) + "px";
  }
  
  this.onMove = function()
  {
    this.repaint();
  }
}
/*
 * Inspector classes
 */
function ConnectorEndsInspector()
{
  this.inspect = function(connector)
  {
    var children = connector.htmlElement.childNodes;
    var i;
    for(i = 0; i < children.length; i++)
    {
      if(hasClass(children[i], "connector-end"))
      {
        var newElement = new ConnectorEnd(connector, children[i], connector.segment3);
        newElement.repaint();
        connector.moveListeners.push(newElement);
      }
      else if(hasClass(children[i], "connector-start"))
      {
        var newElement = new ConnectorEnd(connector, children[i], connector.segment1);
        newElement.repaint();
        connector.moveListeners.push(newElement);
      }
    }
  }
}
function ConnectorLabelsInspector()
{
  this.inspect = function(connector)
  {
    var children = connector.htmlElement.childNodes;
    var i;
    for(i = 0; i < children.length; i++)
    {
      if(hasClass(children[i], "source-label"))
      {
        var newElement = new SideConnectorLabel(connector, children[i], "source");
        newElement.repaint();
        connector.moveListeners.push(newElement);
      }
      else if(hasClass(children[i], "middle-label"))
      {
        var newElement = new MiddleConnectorLabel(connector, children[i]);
        newElement.repaint();
        connector.moveListeners.push(newElement);
      }
      else if(hasClass(children[i], "destination-label"))
      {
        var newElement = new SideConnectorLabel(connector, children[i], "destination");
        newElement.repaint();
        connector.moveListeners.push(newElement);
      }
    }
  }
}
/*
 * Inspector registration
 */
inspectors.push(new ConnectorEndsInspector());
inspectors.push(new ConnectorLabelsInspector());
/*
 * an array containing all the canvases in document
 */
var canvases = new Array();
/*
 * This function initializes the js_graph objects inspecting the html document
 */
function initPageObjects()
{
  if(isCanvas(document.body))
  {
    var newCanvas = new Canvas(document.body);
    newCanvas.initCanvas();
    canvases.push(newCanvas);
  }
  else
  {
  
  var divs = document.getElementsByTagName("div");
  var i;
  for(i = 0; i < divs.length; i++)
  {
    if(isCanvas(divs[i]))
    {
      var newCanvas = new Canvas(divs[i]);
      newCanvas.initCanvas();
      canvases.push(newCanvas);
    }
  }
  }
}

/*
 * Utility functions
 */

function findCanvas(canvasId)
{  
  var i;
  for(i = 0; i < canvases.length; i++)
    if(canvases[i].id == canvasId)
      return canvases[i];
  return null;
}
function findBlock(blockId)
{
  var i;
  for(i = 0; i < canvases.length; i++)
  {
    var block = canvases[i].findBlock(blockId);
    if(block)
      return block;
  }
  return null;
}
 
/*
 * This function determines whether a html element is to be considered a canvas
 */
function isBlock(htmlElement)
{
  return hasClass(htmlElement, "block");
}
/*
 * This function determines whether a html element is to be considered a block
 */
function isCanvas(htmlElement)
{
  return hasClass(htmlElement, "canvas");
}
/*
 * This function determines whether a html element is to be considered a connector
 */
function isConnector(htmlElement)
{
  return htmlElement.className && htmlElement.className.match(new RegExp("connector .*"));
}
/*
 * This function calculates the absolute "top" value for a html node
 */
function calculateOffsetTop(obj)
{
  var curtop = 0;
  if (obj.offsetParent)
  {
    while (obj.offsetParent)
    {
      curtop += obj.offsetTop;
      obj = obj.offsetParent;
    }
  }
  else if (obj.y)
    curtop += obj.y;
  return curtop;  
}
/*
 * This function calculates the absolute "left" value for a html node
 */
function calculateOffsetLeft(obj)
{
  var curleft = 0;
  if (obj.offsetParent)
  {
    while (obj.offsetParent)
    {
      curleft += obj.offsetLeft;
      obj = obj.offsetParent;
    }
  }
  else if (obj.x)
    curleft += obj.x;
  return curleft;              
}

function hasClass(element, className)
{
  if(!element.className)
    return false;
    
  var classes = element.className.split(" ");
  var i;
  for(i = 0; i < classes.length; i++)
    if(classes[i] == className)
      return true;
  return false;
}
/**
 * This function retrieves the actual value of a style property even if it is set via css.
 */
function getStyle(node, styleProp)
{
  // if not an element
  if( node.nodeType != 1)
    return;
    
  var value;
  if (node.currentStyle)
  {
    // ie case
    styleProp = replaceDashWithCamelNotation(styleProp);
    value = node.currentStyle[styleProp];
  }
  else if (window.getComputedStyle)
  {
    // mozilla case
    value = document.defaultView.getComputedStyle(node, null).getPropertyValue(styleProp);
  }
  
  return value;
}
function replaceDashWithCamelNotation(value)
{
  var pos = value.indexOf("-");
  while(pos > 0 && value.length > pos + 1)
  {
    value = value.substring(0, pos) + value.substring(pos + 1, pos + 2).toUpperCase() + value.substring(pos + 2);
    pos = value.indexOf("-");
  }
  return value;
}
</script>

<style rel="stylesheet" type="text/css">
.draggable
{
  position: absolute;
  cursor: move;
}
.connector
{
  background-color: black;
}
.dock_point
{
  height: 1px;
  width: 1px;
  overflow: hidden;
  padding: 0px !important;
  border: none !important;
  margin: 0px;
  position: absolute;
  font-size: 1px;
  visibility: hidden;
}
div.block
{
  border: 1px solid #262A37;
  background-color: #E0E8FF;
  padding: 5px;
  font-size: 11px;
}
html
{
  padding: 0px;
  margin: 0px;
}
body
{
  font-family: verdana;
  color: #33333F;
  padding: 3px;
  margin: 0px;
  background-color: white;
}
h1
{
  color: #FF7521;
  margin: 0px;
}
h2
{
  font-size: 15px;
  margin: 0px;
}
.middle-label, .source-label, .destination-label
{
  font-size: 11px;
  font-weight: bold;
  padding: 5px;
}
div.connector
{
  background-color: #FF9900;
}
table.main_table 
{
  width: 100%; 
  border-collapse: separate;
}
  
td.menu
{
  padding: 5px;
}
.menu ul
{
  margin: 0px;
  padding: 0px;
  list-style-type: none;
  list-style-position: outside;
}
.menu li
{
  border: none;
  padding: 0px;
  font-size: 12px;
  margin-bottom: 3px;
}
.menu li a
{
  display: block;
  border: 1px solid #262A37;
  width: 100px;
  color: #262A37;
  text-decoration: none;
  padding: 1px;
  background-color: #E0E8FF;
}
.menu li a#active_menu
{
  color: #FF9900;
  border-color: #FF9900;
}
.menu li a:hover
{
  color: #FF9900;
  border-color: #FF9900;
}
</style>


</head>
<body onload="initPageObjects();">
  <table class="main_table">
    <tr>
      <td style="vertical-align: top; padding: 0px;">
      <div id="mainCanvas" class="canvas block" style="width: 100%; height: 400px; background-color: white; padding: 0px;">
        <div id="title_block" class="block draggable" style="top: 100px; left: 100px;">
          <h2>Coming soon...</h2>
        </div>
      </td>
    </tr>
  </table>
  <div class="connector active_menu mainCanvas">
  </div>
  </body>
</html>


<A href="http://www.wbex.ru/Code/JavaScriptDownload/dragdrop.zip">dragdrop.zip( 15 k)</a>


ViewPane and Explorer

<html>
<head>
<title>DynAPI Examples - ViewPane and Explorer</title>
<script language="JavaScript" src="./dynapisrc/dynapi.js"></script>
<script language="Javascript">
  dynapi.library.setPath("./dynapisrc/");
  dynapi.library.include("dynapi.api");
  dynapi.library.include("ViewPane");
  dynapi.library.include("Explorer");
  dynapi.library.include("ExplorerBlockStyle"); //Optional
</script>
<script language="Javascript">
  var html;
  var vp = new ViewPane(null,250,100,200,160);
  // optional corner image
  vp.setLocalStyleAttribute("imageCorner",Styles.getImage("corner.gif",16,16));
  var env = dynapi.functions.getImage("./dynapiexamples/images/envelope.gif",15,18);
  var exp2 = new Explorer(0,0,null,null,"ExplorerBlock");
  exp2.addLeave("root","<font color="green"><b>Emails<b></font>");
    // Inboox
    exp2.addLeave("ib","<font color="Navy"><b>Inbox<b></font>","root");
    exp2.addLeave("flour","<font color="red">Just stop to say Hi..<br>Be of good cheer</font><hr>","ib",env);
    exp2.addLeave("sugar","<font color="black">This is a very long message<br>with a lot of <br>breaks...</font><hr>","ib",env);
    exp2.addLeave("choc","Chocolate","ib",env);
      // Archive
      exp2.addLeave("ar","Archive","ib");
      exp2.addLeave("plain","Plain Cake","ar",env);
      exp2.addLeave("ccake","Chocolate Cake","ar",env);
    // Outbox
    exp2.addLeave("ob","<font color="maroon"><b>Outbox<b></font>","root");
    exp2.addLeave("mango","Mango","ob",env);
    exp2.addLeave("apple","Apple","ob",env);
    exp2.addLeave("grape","Grapes","ob",env);
  vp.setContent(exp2);
  dynapi.document.addChild(vp);
</script>
</head>
<body>
<script>
  dynapi.document.insertAllChildren();
</script>
</body>
</html>


<A href="http://www.wbex.ru/Code/JavaScriptDownload/dynapi.zip">dynapi.zip( 791 k)</a>


View Pane and Load Panel

<html>
<head>
<title>DynAPI Examples - ViewPane and LoadPanel</title>
<script language="JavaScript" src="./dynapisrc/dynapi.js"></script>
<script language="Javascript">
  dynapi.library.setPath("./dynapisrc/");
  dynapi.library.include("dynapi.api");
  dynapi.library.include("dynapi.gui.LoadPanel");
  dynapi.library.include("ViewPane");
</script>
<script language="Javascript">
  var lp = new LoadPanel("./dynapiexamples/loadpanel/file1.html");
  lp.setSize(300,300);
  lp.setBgColor("#C0C0C0");
  var vp = new ViewPane(null,250,100,200,200);
  vp.setContent(lp)
  dynapi.document.addChild(vp);
</script>
</head>
<body>
<p>
<a href="javascript:lp.setURL("./dynapiexamples/loadpanel/file1.html")">file 1</a><br>
<a href="javascript:lp.setURL("./dynapiexamples/loadpanel/file2.html")">file 2</a><br>
<a href="javascript:lp.setURL("./dynapiexamples/loadpanel/file3.html")">file 3</a>
</p>
<script>
  dynapi.document.insertAllChildren();
</script>
</body>
</html>


<A href="http://www.wbex.ru/Code/JavaScriptDownload/dynapi.zip">dynapi.zip( 791 k)</a>