/******************************************************************************
vegUI Site Kit 

Copyright (c) 2005, 2006, 2007 Stefan Pratter

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

Contact: vegu@vegui.org
Website: http://www.vegui.org
**/

/******************************************************************************
 * G L O B A L S **************************************************************
 *****************************************************************************/

var VSK_VERSION = '0.1.5';

/* initiated the browser information object that will later hold the information * about the browser being used
 */

var VSK_I = {
  name : null
};

/* find browser name, we only need to scane for mozilla, ie and opera since
 * those are the only browsers we care about
 */

if(window.opera) {
  VSK_I.name = 'Opera';
} else if (navigator.userAgent) {
  var str = navigator.userAgent;
  if(str.indexOf("Firefox") != -1) {
    VSK_I.name = 'Firefox';
  } else if(str.indexOf("Netscape") != -1) {
    VSK_I.name = 'Netscape';
  } else if(str.indexOf("MSIE") != -1) {
    VSK_I.name = 'MSIE';
  } else if(str.indexOf("Gecko") != -1) {
    VSK_I.name = 'Mozilla';
  }
}

/* Sniff Browser Version */

VSK_I.version = vsk_browser_version();

/******************************************************************************
 * F U N C T I O N S **********************************************************
 *****************************************************************************/

/*****************************************************************************/
/** Function: v
  * Returns VSK_Node object that controlls the submitted node
  *
  * Paramters:
  *
  *	Node node - node to control
  *
  * Returns:
  *
  *	VSK_Node object
  *
  */

function v(node) {
  return new VSK_Node(node);
}

/*****************************************************************************/
/** Function: V
  * Returns VSK_node object that controls the node with the submitted
  * id
  *
  * Parameters:
  *
  *	var id - id of the node to control
  *
  * Returns:
  *
  *	VSK_Node - if node could be retrieved
  *	null - if no node with specified id was found in the document
  */

function V(id) {
  var n = document.getElementById(id);
  return (n ? v(n) : null);
}

/*****************************************************************************/
/** Function: vsk_html_node
  * Returns a new node 
  *
  * Alias:
  *
  *	vsk_h()
  *
  * Parameters:
  *
  *	string nodeName - tag/node name of the node to create
  *	<string className> - if submitted the created node will use
  *	this css class
  *	<Node parentNode> - if submitted the created node will be appended
  *	to this node
  *	<var id> - if submitted the created node will have its id
  *	property set
  *
  * Returns:
  *
  *	Node - created node
  */

vsk_html_node = vsk_h = function(nodeName, className, parentNode, id) {
  var n = document.createElement(nodeName);
  if(className)
    n.className = className;
  if(parentNode) {
    v(n).dock(parentNode);
  } 
  if(id)
    n.id = id;
  return n;
};

/*****************************************************************************/
/** Function: vsk_txt_node
  * Create and return a text node
  *
  * Alias:
  *
  *	vsk_t()
  *
  * Parameters:
  *
  *	string text - text to create
  *	<Node parentNode> - if submitted the created text node will be appended
  *	to the node
  *
  * Returns:
  *
  *	TextNode - created text node
  */

vsk_txt_node = vsk_t = function(text, parentNode) {
  var n = document.createTextNode(text);
  v(n).dock(parentNode);
  return n;
};

/*****************************************************************************/
/** Function: vsk_get_mouse
  * sets vskX and vskY to the current mouse coordinates
  *
  * Parameters:
  *
  *	Event e - event object
  */

function vsk_get_mouse(e) {
  if (e.pageX || e.pageY) {
    vskX = e.pageX;
    vskY = e.pageY;
  }
  else if (e.clientX || e.clientY) {
    vskX = e.clientX + document.documentElement.scrollLeft;
    vskY = e.clientY + document.documentElement.scrollTop;
  }
}

/***************************************************************************/
/** Method: vsk_rel_target
  *
  * Returns the related target of a mouse event (cross browser support)
  *
  * Parameters:
  *
  *	Event e - event object
  *	
  *
  */

function vsk_rel_target(e) {
  if(!e)
    var e = event;
  return (
    e.relatedTarget ?
    e.relatedTarget : (
      e.type == 'mouseover' ?
      e.fromElement :
      e.toElement
    )
  );
}

/*****************************************************************************/
/** Function: pi
  * Wrapper function for parseInt
  */

function pi(str) {
  return parseInt(str);
}
window.vskpi = parseInt;

/*****************************************************************************/
/** Function: in_array
  * check if a value exists inside an array 
  *
  * Parameters:
  *
  *	array arr - array to check
  *	var value - value to look for
  *
  * Returns:
  *
  *	bool - true if value exists in array
  *	bool - false if value does not exist in array
  */

function in_array(arr, value) {
  var i;
  for(i = 0; i < arr.length; i++) {
    if(arr[i] == value)
      return true
  }
  return false;
}

/*****************************************************************************/
/** Function: vsk_rand
  * Returns a random number
  *
  * Parameters:
  *
  *	int min - minimum number
  *	int max - maximum number
  *
  * Returnd:
  *
  *	int - a random number between min and max
  */

function vsk_rand(min, max) {
  return (Math.round(Math.random()*max)+min);
}

/*****************************************************************************/
/** Function: vsk_browser_version
  * Returns browser version
  *
  */

function vsk_browser_version() {
  
  var name = VSK_I.name, str, index;

  if(name == 'Mozilla')
    name == 'rv';

  if( !(str = navigator.userAgent) && !(str = navigator.appVersion) )
    return 0;
  if( (index = str.indexOf(name)) == -1)
    return 0;
  return parseFloat(str.substring(index+name.length+1));
}


/******************************************************************************
 * V S K  N O D E *************************************************************
 *****************************************************************************/
/** Class: VSK_Node */

function VSK_Node(node) {
  
  this.control(node);
  
}

/*****************************************************************************/
/** Method: abs_x
  * Returns the x position of the element relative to the document or a
  * specified parent element
  *
  * Parameters:
  *
  *	<Node Parent> - if submitted the position will be relative to this
  *	parent node
  *
  * Returns:
  *
  *	int - x position of the element
  */

VSK_Node.prototype.abs_x = function(Parent) {
  if(!this.b)
    return null;

  var n = this.b, x = 0, o;
  while(n && n.parentNode && n.parentNode.style && (!Parent || Parent != n)) {
    x += n.offsetLeft;
    if(v(n).s.left === '')
      n = n.offsetParent;
    else
      n = n.parentNode;
    if(n == document.body)
      break;
  }

  return x;
};

/*****************************************************************************/
/** Method: abs_y
  * Returns the y position of the element relative to the document or a
  * specified parent element
  *
  * Parameters:
  *
  *	<Node Parent> - if submitted the position will be relative to this
  *	parent node
  *
  * Returns:
  *
  *	int - y position of the element
  */

VSK_Node.prototype.abs_y = function(Parent) {
  if(!this.b)
    return null;

  var n = this.b, y = 0;
  while(n && n.parentNode && n.parentNode.style && (!Parent || Parent != n)) {
    y += n.offsetTop;
    if(v(n).s.top === '')
      n = n.offsetParent;
    else
      n = n.parentNode;
    if(n == document.body)
      break;
  }
  return y;
};

/***************************************************************************/
/** Method: ga
  * Get attribute or default value if attribute is not set for node
  *
  * Parameters:
  *
  *	string name - attribute name
  *	mixed d - value returned if attribute is not set for node
  * 
  * Returns:
  *
  *	string - attribute
  */

VSK_Node.prototype.ga = function(name,d) {
  if(!this.b || typeof this.b.getAttribute == 'undefined')
    return null;
  var v = this.b.getAttribute(name);
  return (v ? v : d);
};

/***************************************************************************/
/** Method: bbox
  * Enable and set bounding box parameters. All position parameters
  * are to be on the same plane as the element.
  *
  * Parameters:
  *
  *	int x - x position of bounding box (px)
  *	int y - y position of bounding box (px)
  *	int w - width of bounding box (px)
  *	int h - height of bounding box (px)
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.bbox = function(x, y, w, h) {
  this.b.vskBBox = {
    x : x,
    y : y,
    w : w,
    h : h,
    r : x+w,
    b : y+h
  };
  return this;
};

/***************************************************************************/
/** Method: bbox_tgl
  * Toggle bounding box on or off 
  *
  * Parameters:
  *
  *	bool b - true = on, false = off
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.bbox_tgl = function(b) {
  if(!b && this.b.vskBBox) {
    this.b.vskBBoxTmp = this.b.vskBBox;
    this.b.vskBBox = null;
  } else if(b && this.b.vskBBoxTmp) {
    this.b.vskBBox = this.b.vskBBoxTmp;
    this.b.vskBBoxTmp = null;
  }
  return this;
};

/***************************************************************************/
/** Method: clear
  * Removes all the child nodes of the node
  *
  * Paramters: 
  *
  *	<Node node> - optional node to append to this node after clearing
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.clear = function(node) {
  
  if(!this.b)
    return;

  while(this.b.childNodes[0])
    this.b.removeChild(this.b.childNodes[0]);
  if(node)
    this.b.appendChild(node);

  return this;
};

/***************************************************************************/
/** Method: control
  * Takes control of another node
  *
  * Parameters:
  *
  *	Node node - node to take control of
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.control = function(node) {
  if(!node)
    return;
  this.b = node;
  this.s = node.style;
  return this;
};

/***************************************************************************/
/** Method: dock
  * 
  * Appends node to the submitted node as a child
  *
  * Parameters:
  *
  *	Node toNode - node to append to
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.dock = function(toNode) {
  if(this.b && toNode) {
    toNode.appendChild(this.b);
    this.vsk_event_fire('dock');
  }
  return this;
};

/***************************************************************************/
/** Method: event_unset 
  * 
  * Method to unset a previously set event listener on the node
  *
  * Parameters:
  *
  *	string eventName - name of the event (ie. 'click' or 'mousedown')
  *	string id - id that you used to set the eventlistener
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.event_unset = function(eventName, id) {
  if(!this.b || !this.b.vskEvents)
    return this;
  
  var func;
  
  if(this.b.vskEvents[eventName] && (func = this.b.vskEvents[eventName][id])) {
    if(this.b.removeEventListener)
      this.b.removeEventListener(eventName, func, false);
    else if(this.b.detachEvent)
      this.b.detachEvent('on'+eventName, func);
    delete this.b.vskEvents[eventName][id];
  }
  
};

/***************************************************************************/
/** Method: event_add
  *
  * Method set an event listener on the node (cross browser supported)
  *
  * Parameters:
  *
  *   string eventName - name of the event (ie. 'click' or 'mousedown')
  *   function func - function to be added
  *   <string id> - unique id, needed if you wish to unset the event
  *   later on
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.event_add = function(eventName, func, id) {
  if(!this.b)
    return this;     

  if(id) {
    this.event_unset(id);
  }

  if(this.b.addEventListener)
    this.b.addEventListener(eventName, func, false);
  else if(this.b.attachEvent)
    this.b.attachEvent('on'+eventName, func);
  
  if(!this.b.vskEvents)
    this.b.vskEvents = {};
  if(!this.b.vskEvents[eventName])
    this.b.vskEvents[eventName] = [];
  
  if(id)
    this.b.vskEvents[eventName][id] = func;
  else
    this.b.vskEvents[eventName].push(func);
  
  return this;
};

/***************************************************************************/
/** Method: events_clear
  * Remove all event listeners
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.events_clear = function() {
  
  if(this.b.vskEvents) {
    var i,n,E = this.b.vskEvents;
    for(i in E) {
      for(n in E[i])
        this.event_unset(i, n);
    }
  }

  
  return this;
};

/***************************************************************************/
/** Method: fade
  * Sets the transparency of the node to the selected value
  *
  * Parameters:
  *
  *	int n - transparency value (percent)
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.fade = function(n) {
  if(!this.s)
    return;
  if(n > 100)
    var n = 100;
  else if(n < 1)
    var n = 1;

  this.s.filter = 'alpha(opacity=' + n +')';
  this.s.opacity = n / 100;
  this.s.MozOpacity = n / 100;
  return this;
};

/***************************************************************************/
/** Method: h
  * Returns the height of the node
  *
  * Parameters:
  *
  *	<bool o> - if set to true the node's offsetHeight attribute
  *	is returned even if the style.height attribute is set.
  *
  * Returns:
  *
  *	int - height of the node
  */

VSK_Node.prototype.h = function(o) {
  if(!this.s)
    return;

  return (this.s.height && !o  ? pi(this.s.height) : this.b.offsetHeight);
};

/**************************************************************************/
/** Function: handle
  * Toggle VSK event handling on for mouse and keyboard events.
  *
  * Alias:
  *
  *     handle()
  *
  * Paramters:
  *
  *     string eventName - name of event e.g "mouseup" or "keydown"
  *
  * Returns:
  *
  *     VSK_Node- self
  */

VSK_Node.prototype.handle = function(eventName) {
  var E = this;
  this.b["on"+eventName] = function(e) {
    if(!e)
      var e = event;
    E.vsk_event_fire(eventName, e);
  };
  return this;
};


/***************************************************************************/
/** Method: has_parent
  *
  * Check if a node is the parent of the controlled node somewhere
  * down the parentNode list
  *
  * Parameters:
  *
  *	Node parentNode - node to check
  *
  * Returns:
  *
  *	bool - true when parentNode is the parent of this node somewhere
  *	down the parentNode chain
  *	bool - false when not
  */

VSK_Node.prototype.has_parent = function(parentNode) {
 var _p = this.b;
  if(!_p) return false;
  while((_p = _p.parentNode)) {
    if(_p == parentNode)
      return true;
  }
  return false;
};

/***************************************************************************/
/** Method: hide
  * Hides or shows the node
  *
  * Paramters:
  *
  *	bool hide - if true node will be hidden, if false node will be 
  *	shown
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.hide = function(hide) {
  if(this.s) {
    this.s.visibility = (hide ? 'hidden' : '');
    this.vsk_event_fire('hide');
  }
  return this;
};

/*****************************************************************************/
/** Method: html_append
  *
  * Append multiple nodes to this node as children
  *
  * Alias: 
  *
  *	html_a()
  *
  * Parameters:
  *
  *	Node node1 - node to append to this node as child
  *	Node node2 - node to append to this node as child
  *	... - additional nodes
  *
  * Returns:
  *
  *	Node - this.b 
  */

VSK_Node.prototype.html_append = function() {
  if(!this.b)
    return;
    
  var i;
  for(i = 0; i < arguments.length; i++) {
    v(arguments[i]).dock(this.b);
  }
  return this.b;
};
VSK_Node.prototype.html_a = VSK_Node.prototype.html_append;

/***************************************************************************/
/** Method: html_insert_after
  * Inserts a html node after this html node
  *
  * Alias:
  *
  *	html_ia()
  *
  * Parameters:
  *
  *	Node ... - node(s) to insert
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.html_insert_after = function() {
  if(!this.b || !this.b.parentNode)
    return this;
  
  var i, node = this.b, p = this.b.parentNode;
  for(i = 0; i < arguments.length; i++) {
    if(node.nextSibling)
      p.insertBefore(arguments[i], node.nextSibling);
    else
      p.appendChild(arguments[i]);
    node = arguments[i];
  }
  return this;
};
VSK_Node.prototype.html_ia = VSK_Node.prototype.html_insert_after;

/***************************************************************************/
/** Method: html_insert_before
  * Insert one or more html nodes before this node
  *
  * Alias:
  *
  *	html_ib()
  *
  * Parameters:
  *
  *	Node ... - html nodes to insert
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.html_insert_before = function() {
  if(!this.b || !this.b.parentNode)
    return this;
  var i;
  for(i = 0; i < arguments.length; i++) 
    this.b.parentNode.insertBefore(arguments[i], this.b);
  return this;
};
VSK_Node.prototype.html_ib = VSK_Node.prototype.html_insert_before;

/***************************************************************************/
/** Method: level
  * Set z-Index of node
  *
  * Parameters:
  *
  *	int z - z index
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.level = function(z) {
  this.s.zIndex = z;
  return this;
};

/***************************************************************************/
/** Method: move 
  *
  * Moves the node to a new position
  *
  * Parameters:
  *
  *	int x - new position on the x axis (px, left)
  *	int y - new position on the y axis (px, top)
  *	<int x2> - new position on the x axis (px, right, overwrites x)
  *	<int y2> - new position on the y axis (px, bottom, overwrites y)
  *
  * Note:
  *
  *	Bounding box will currently only apply on x,y movement. Bounding
  *	Box support will be added for x2,y2 movement at a later point
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.move = function(x, y, x2, y2) {
  if(!this.s)
    return;

  this.moveable();

  var B = this.b.vskBBox;

  if( (isNaN(x2) || x2 === null) && !isNaN(x) && x !== null) {
    
    /* apply bounding box if necessary */

    if(B) {
      if(B.x > x) {
        var x = B.x;
	this.vsk_event_fire("bumped_l");
      } else if(B.r < (x+this.w())) {
        var x = B.r - this.w();
	this.vsk_event_fire("bumped_r");
      }
    }
    
    this.s.left = x + 'px';
    this.s.right = '';
    
  } else if(!isNaN(x2) && x2 !== null) {
    this.s.right = x2 + 'px';
    this.s.left = '';
  
  }
    
  if( (isNaN(y2) || y2 === null) && !isNaN(y) && y !== null) {
    
    /* apply bounding box if necessary */

    if(B) {
      if(B.y > y) {
        var y = B.y;
	this.vsk_event_fire("bumped_u");
      } else if(B.b < (y+this.h())) {
        var y = B.b - this.h();
	this.vsk_event_fire("bumped_d");
      }
    }
 

    this.s.top = y + 'px';
    this.s.bottom = '';
  } else if(!isNaN(y2) && y2 !== null) {
    this.s.top = '';
    this.s.bottom = y2 + 'px';
  }

  this.vsk_event_fire('move');
  
  return this;
};

/***************************************************************************/
/** Method: resize
  * 
  * Resizes the node
  *
  * Parameters:
  *
  *	int w - new width (px)
  *	int h - new height (px)
  *
  * Returns:
  *
  *	VSK_Node - self
  */
VSK_Node.prototype.resize = function(w, h) {
  if(!this.s)
    return;
  
  var B = this.b.vskBBox;

  if(w) {
    
   
    /* apply bounding box if necessary */

    if(B) {
      if((this.x() + w) > B.r) {
        var w = B.r - this.x();
        this.vsk_event_fire("bumped_r");
      }
    }
    
    this.s.width = (w<1?1:w) + 'px';
  } if(h) {

   
    /* apply bounding box if necessary */

    if(B) {
      if((this.y() + h) > B.b) {
        var h = B.b - this.y();
	this.vsk_event_fire("bumped_d")
      }
    }
    
    this.s.height = (h<1?1:h) + 'px';
  
  }
  
  this.vsk_event_fire('resize');
  return this;
};

/***************************************************************************/
/** Method: set_pos
  * Sets the css position of the node and the node's z-index
  *
  * Parameters:
  *
  *	strign pos - position ('absolute', 'relative' ...)
  *	<int zIndex> - new zIndex
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.set_pos = function(pos, zIndex) {
  if(pos)
    this.s.position = pos;
  if(!isNaN(zIndex))
    this.s.zIndex = zIndex;
  return this;
};

/***************************************************************************/
/** Method: set_style
  * Allows you to set css styles of the node
  *
  * Parameters:
  *
  *	object|string style - style object that should be treated like the
  *	style object of a html node.
  *
  *	if style is submitted as string then it is assumed to be a
  *	css class name and will be treated as such. (e.g the css class
  *	of the object will be changed)
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.set_style = function(style) {
  var i;
  
  if(!style)
    return this;
  
  if(!style.indexOf) {
    for(i in style) {
      this.s[i] = style[i];
    }
  } else
    this.b.className = style;

  return this.vsk_event_fire("style");
};

/***************************************************************************/
/** Function: set_style_str
  * Allows you to set css styles of the node via string
  *
  * Parameters:
  *
  *	string style - string of css rules
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.set_style_str = function(style) {
  this.b.setAttribute("style", style);
  this.b.style.cssText = style;
  return this.vsk_event_fire("style");
};

/***************************************************************************/
/** Function: style_str
  * Get the style string
  *
  * Returns:
  *
  *	string - css rules
  */

VSK_Node.prototype.style_str = function() {
  return (this.s.cssText || this.ga("style"));
};

/***************************************************************************/
/** Method: moveable
  * If the node is currently positioned static make it's position absolute
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.moveable = function() {
  if(this.s.position == '' || this.s.position == 'static')
    this.set_pos("absolute");
  return this;
};

/***************************************************************************/
/** Method: span
  * Position the upper left corner of the node at x,y and the lower
  * right corner ofthe node at x2,y2
  *
  * Parameters:
  *
  *	int x - x position of the upper left corner
  *	int y - y position of the upper left corner
  *	int x2 - x position of the lower right corner
  *	int y2 - y position of the lower right corner
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.span = function(x, y, x2, y2) {
  this.moveable();
   
  if(this.s) {
    this.s.left = (isNaN(x) || x === null) ? '' : x+'px';
    this.s.top = (isNaN(y) || y === null) ? '' : y+'px';
    this.s.right = (isNaN(x2) || x2 === null) ? '' : x2+'px';
    this.s.bottom = (isNaN(y2) || y2 === null) ? '' : y2+'px';
  }

  this.vsk_event_fire("move");
  this.vsk_event_fire("resize");
  this.vsk_event_fire("span", [x,y,x2,y2]);
  
  return this;
};

/***************************************************************************/
/** Method: set
  * Set Node attribute
  *
  * Parameters:
  *
  *	string name - attribute name
  *	mixed value - attribute value
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.set = function(name, value) {
  this.b.setAttribute(name, value);
  return this;
};

/***************************************************************************/
/** Method: t 
  * Returns the transparency of the node (in percent)
  *
  * Returns:
  *
  *	int - transparency of the node (in percent)
  */

VSK_Node.prototype.t = function() {
  if(!this.s || this.s.opacity === '')
    return 100;

  return (this.s.opacity * 100);
};

/***************************************************************************/
/** Method: trim
  * Removes an unspecified amount of child nodes from the beginning or end
  * of the child nodes array of the controlled node until the defined
  * length is reached
  *
  * Parameters:
  *
  *	int length - trim child nodes to this amount
  *	bool reverse - if true child nodes will be trimmed from the end
  *
  */

VSK_Node.prototype.trim = function(length, reverse) {
  if(!this.b)
    return;

  while(this.b.childNodes.length > length) {
    if(!reverse)
      v(this.b.firstChild).undock();
    else
      v(this.b.lastChild).undock();
  }
};

/***************************************************************************/
/** Method: undock
  * Removes the node from its parentNode
  *
  * Returns:
  *
  * 	VSK_Node - self
  */
  
VSK_Node.prototype.undock = function() {
  if(!this.b || !this.b.parentNode) 
    return this;
  
  this.b.parentNode.removeChild(this.b);
  this.vsk_event_fire('undock');

  return this;
};

/***************************************************************************/
/** Method: v
  * Checks if the node is hidden
  *
  * Returns:
  *
  *	bool - true, if the node is visible
  *	bool - false, if the node is hidden
  *
  */

VSK_Node.prototype.v = function() {
  if(!this.s)
    return;
  return (this.s.visibility == 'hidden' ? false : true);
};

/***************************************************************************/
/** Method: vsk_event_add
  *
  * Adds a vsk specific event handler
  *
  * Parameters:
  *
  *	string name - event name
  *	function func - function to be added to the event handler
  *	<var id> - unique function id so that the added function can
  *	later be removed again from the event handler
  *
  * Valid Events:
  *
  *	resize - when the node is resized using the <resize> method
  *	move - when the node is moved using the <move> method
  *	dock - when the node is docked using the <dock> method
  *	undock - when the node is undocked using the <undock> method
  *	bumped_l - when the bounding box is active and the node
  *	tried to get outside of it's boundaries (left side)
  *	bumped_r - (right side)
  *	bumped_u - (up side)
  *	bumped_d - (down side)
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.vsk_event_add = function(name, func, id) {

  if(!this.b)
    return this;
  
  /* check if the event handle for the selected event exists for the
   * selected node. if it does not, create it
   */

  if(!this.b['vsk_on'+name])
    this.b['vsk_on'+name] = new VegUIDynFunc();

  var F = this.b['vsk_on'+name];
  F.add(func, id);
  return this;
};

/***************************************************************************/
/** Method: vsk_event_fire
  * Triggers the event handler for a certain vsk event
  *
  * Parameters:
  *
  *	string name - name of event to trigger
  *	<array argArr> - optional argument array
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.vsk_event_fire = function(name, argArr) {
  if(!this.b || !this.b['vsk_on'+name])
    return this;

  this.b['vsk_on'+name].execute(this, argArr);
  return this;
};

/***************************************************************************/
/** Method: vsk_event_unset
  * Remove a function from a specific vsk event handler by it's unique
  * function id
  *
  * Parameters:
  *
  *	string name - name of the event handler
  *	var id - unique function id
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.vsk_event_unset = function(name, id) {
  if(!this.b || !this.b['vsk_on'+name])
    return this;

  this.b['vsk_on'+name].free(id);
  return this;
};

/***************************************************************************/
/** Method: w
  * Returns the width of the node
  *
  * Parameters: 
  *
  *	<bool o> - if true the node's offsetWidth attribute will be
  *	returned even if the style.width attribute is set
  *
  * Returns:
  *
  *	int - width of the node
  */

VSK_Node.prototype.w = function(o) {
  if(!this.s)
    return;

  return (this.s.width && !o ? pi(this.s.width) : this.b.offsetWidth);
};

/***************************************************************************/
/** Method: x
  * returns x position of the node
  *
  * Returns:
  *
  *	int - x position of the node
  */

VSK_Node.prototype.x = function() {
  if(!this.s)
    return;
  return (this.s.left !== '' ? pi(this.s.left) : this.b.offsetLeft);
};

/***************************************************************************/
/** Method: x2
  * Returns the right x position of the node
  * 
  * Returns:
  * 
  *	int - x position of the right border of the node
  */

VSK_Node.prototype.x2 = function() {
  if(!this.s)
    return;

  return (this.w()+this.x());
};


/***************************************************************************/
/** Method: y 
  * returns y position of the node
  *
  * Returns:
  *
  *	int - y position of the node
  */

VSK_Node.prototype.y = function() {
  if(!this.s)
    return;
  return (this.s.top !== '' ? pi(this.s.top) : this.b.offsetTop);
};

/***************************************************************************/
/** Function: y2 
  * Returns the y bottom position of the node
  *
  * Returns:
  *
  *	int - position of the node's bottom border on the y axis
  *
  */

VSK_Node.prototype.y2 = function() {
  if(!this.s)
    return;

  return this.h()+this.y();
};

/***************************************************************************/
/** Method: z
  * returns zindex of node
  *
  * Returns:
  *
  *	int - z-index of node
  */

VSK_Node.prototype.z = function() {
  if(!this.s)
    return;
  return this.s.zIndex;
};

/******************************************************************************
 * D Y N F U N C **************************************************************
 *****************************************************************************/
 /** Class: VegUIDynFunc
   * Allows to have a function with dynamic content 
   *
   * Properties: Object Properties
   *
   * 	Funcs - *Array*, holds the functions
   *	returnVal - *variable*, holds the value that will be returned by the
   *	<execute> method
   *
   */

/*****************************************************************************/
/** Constructor: VegUIDynFunc 
  *
  * *Constructor*
  *
  * Parameters:
  *
  *	var returnVal - value to be returned by the <execute> method
  *
  */

function VegUIDynFunc(returnVal) {
  this.Funcs = {
    _l : 0,
    _p : function(fn) {
      this[this._l] = fn;
      this._l++;
    }
  };
  this.returnVal = returnVal || false;

  /***************************************************************************/
  /** Method: add
    * 
    * Adds a function to the stack
    *
    * Parameters:
    *
    *	function fn - function to be added to the stack
    *	var id - unique id string
    *
    * Code example:
    *
    * (start code)
    * myDynFunc.add(function() { alert('hi'); }, 'hi');
    * (end)
    *
    * See also:
    *
    * 	<free>
    */

  this.add = function(fn,id) { 
    
    if(id) {
      this.Funcs[id] = fn;
    }
    else
      this.Funcs._p(fn);
  };

  /***************************************************************************/
  /** Method: execute
    *
    * Executes all the functions in the stack
    *
    * Parameters:
    *
    *	<Object object> - object of reference
    *	<Array ArgArr> - Array that can hold various parameters. In order for
    *	functions in the stack to be able to work with the argArr argument
    *	they need to be defined with it in mind
    *
    * Code example:
    *
    * (start code)
    * myDynFunc.add( function(argArr) { alert(argArr[0]); } );
    * myDynFunc.execute(['hello world']);
    * (end)
    *
    * Returns:
    *
    *	variable - returns the value of this.returnValue
    *
    */

  this.execute = function(obj, argArr) {
    var i, returnVal = this.returnVal;
    for(i in this.Funcs) {
      if(typeof this.Funcs[i] != 'function' || i == '_p')
        continue;
      this.Funcs[i](obj, argArr);
    }
    return returnVal;
  };

  /***************************************************************************/
  /** Method: free
    *
    * Free a unique function id effectivly removing the function linked to
    * it from the stack
    *
    * Parameters:
    *
    *	variable id - unique function id
    *
    * See also:
    *
    *	<add>
    */

  this.free = function(id) { delete this.Funcs[id]; };
}


/******************************************************************************
 * G L O B A L S **************************************************************
 *****************************************************************************/
/** File: vegui.sk.debug.js
  *
  * Dependencies:
  *
  *	<vegui.sk.std.js>	
  */

/*****************************************************************************/
/** Function: vsk_dbg_start
  * Starts debug mode that creates a text label attached to the borders
  * of the document that messages can then be printed to using
  * <vsh_dbg_print>
  *
  * Parameters:
  *
  *	string attachTo - defines where the debug console will be attached to
  *	<int lines> - define possible amount of lines in the console at the
  *	same time, default: 100
  *	<int h> - height of the console (pixels), default: 100
  *	<int w> - width of the console, only relevant when attaching console
  *	into a corner, default: 300
  *	
  * attachTo values:
  *
  *	't' - top side of the document
  *	'b' - bottom side of the document
  *	'ul' - upper left side of the document
  *	'lr' - lower right side of the document
  *
  * See also:
  *
  *	<vsk_dbg_stop>
  */

function vsk_dbg_start(attachTo, lines, w, h) {
  
  if(!lines)
    var lines = 100;
 
  var c = v(vsk_h('div','',null,'vsk_dbg_console'));
  c.s.position = 'absolute';
  c.s.zIndex = 100000;
  c.s.border = '1px #000 solid';
  c.s.backgroundColor = '#fff';
  c.s.font = '10px Verdana, Arial, Helvetica';
  c.s.overflow = 'auto';
  c.b.vskConsoleLines = lines;
  c.dock(document.body);

  vsk_dbg_adjust(attachTo, w, h);

  /* make sure console gets adjusted to it's correct postion when the
   * window is resized or scrolled
   */

  v(window).event_add('scroll', function() {
    vsk_dbg_adjust();
  });

  v(window).event_add('resize', function() {
    vsk_dbg_adjust();
  });

  /* when the console is clicked it should switch to the next dock
   * position
   */

  c.event_add('mousedown', function() {
    var c;
    if(!(c = V('vsk_dbg_console')))
      return;

    switch(c.b.vskConsolePos) {
      case 'b': vsk_dbg_adjust('t'); break;
      case 't': vsk_dbg_adjust('ul',w,h); break;
      case 'ul': vsk_dbg_adjust('lr',w,h); break;
      case 'lr': vsk_dbg_adjust('b'); break;
    }
    
  });

  
}

/*****************************************************************************/
/** Function: vsk_dbg_adjust
  * Moves the console to its designated spot taking scroll offset into mind
  *
  * Parameters:
  *
  *	<string attachTo> - defines the position the console will be locked
  *	to, if ommited then the current position will be refreshed
  *	<int w> - width of the console, only relevant when the console
  *	is attached to a corner, default: 300 (px)
  *	<int h> - height of the console, default: 100 (px) 
  *
  */

function vsk_dbg_adjust(attachTo, w, h) {

  var c;
  if(!(c = V('vsk_dbg_console')))
    return;

  if(!attachTo)
    attachTo = c.b.vskConsolePos;

  if(!h)
    var h = 100;
  if(!w)
    var w = 300;
 
  
  var y = vsk_oy(), x = vsk_ox(), wH = vsk_ih(), wW = vsk_iw();

  switch(attachTo) {
    case 't': 
      c.resize(wW,h).move(0,0+y+10);
    break;
    case 'b':
      c.resize(wW,h).move(0,((wH-h)+y)-30);
    break;
    case 'ul':
      c.resize(w,h).move(20+x,20+y);
    break;
    case 'lr':
      c.resize(w,h).move( ((wW-w)+x)-20, ((wH-h)+y)-30);
    break;
  }
  
  c.b.vskConsolePos = attachTo;
 
}


/*****************************************************************************/
/** Function: vsk_dbg_stop
  * Stops debug mode
  */

function vsk_dbg_stop() {
  V('vsk_dbg_console').undock();
}

/*****************************************************************************/
/** Function: vsk_dbg_print
  * Print a message to the debug console on a new line
  *
  * Parameters:
  *
  *	string msg - text to print tothe console
  *	<string color> - font color 
  */

function vsk_dbg_print(msg, color) {
  var c;
  if(!(c = V('vsk_dbg_console')))
    return;
  
  var d = v(vsk_h('div')).html_append(vsk_t(msg));
  if(color)
    d.style.color = color;
  c.html_append(d);
  c.trim(c.b.vskConsoleLines);
  c.b.scrollTop = c.b.scrollHeight - c.b.clientHeight;
}
/*
Copyright (c) 2007 Stefan Pratter

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

/******************************************************************************
 * G L O B A L S **************************************************************
 *****************************************************************************/
/** File: vegui.sk.ani.js
  *
  * Dependencies:
  *
  *	<vegui.sk.std.js>
  *
  * Description:
  *
  * The vegUI site kit effect foundation library. All effects build on this 
  * library as it provides functions to handle the global effect timer and to ad  * d and remove effects from nodes handled with the <VSK_Node> object
  *
  */

var vsk_fxInterval;

/** Variable: vsk_Effects
  * Array that holds nodes that currently have vsk effects affecting them
  */

var vsk_Effects = [];

/** Constant: VSK_FX_INTERVAL
  * Interval speed of the global effect timer (ms)
  */

var VSK_FX_INTERVAL = 25;

/*****************************************************************************/
/** Function: vsk_fx_poll
  * Poll nodes in the vsk_Effects array and process their attached effects
  */

function vsk_fx_poll() {
  var i,n;
  for(i = 0; i < vsk_Effects.length; i++) {
    v(vsk_Effects[i]).fx_process();
  }
}

/******************************************************************************
 * E X T E N D  V S K  N O D E ************************************************
 *****************************************************************************/
/** Class: VSK_Node */
/*****************************************************************************/
/** Function: fx_process() 
  * Process all effects currently active on the node
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.fx_process = function() {
  if(!this.b || !this.b.vsk_effects)
    return null;
 
  var i,e;
  for(i in this.b.vsk_effects) {
    if(typeof this.b.vsk_effects[i].main == 'function')
      this.b.vsk_effects[i].main();
  }
  return this;
};

/*****************************************************************************/
/** Function: fx_clear
  * Clears effects by id
  *
  * Parameters:
  *
  *	array clearEffects - array holding effect ids to be cleared
  */

VSK_Node.prototype.fx_clear = function(clearEffects) {
  if(clearEffects && clearEffects.length) {
    var i;
    for(i = 0; i < clearEffects.length; i++)
      this.fx_halt(clearEffects[i], true);
  }
};


/*****************************************************************************/
/** Function: fx_start
  * Start the global effect timer
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.fx_start = function() {
  this.fx_stop();
  vsk_fxInterval = setInterval(vsk_fx_poll, VSK_FX_INTERVAL);
  return this;
};

/*****************************************************************************/
/** Function: fx_stop
  * Stop the global effect timer
  *
  * Returns:
  *
  *	VSK_Node - self
  */


VSK_Node.prototype.fx_stop = function() {
  vsk_fxInterval = clearInterval(vsk_fxInterval);
  return this;
};

/*****************************************************************************/
/** Function: fx_init
  * Initialize effect on node
  *
  * Parameters:
  *
  *	var id - unique effect id
  *	object effect - effect object
  *	<array collision> - every existing value will be treated as an
  *	effect id, any effect ids active on the object that are found
  *	in the collision array will be canceled
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.fx_init = function(id, effect, collision) {
  if(this.b) {
    if(!this.b.vsk_effects)
      this.b.vsk_effects = {};
    this.b.vsk_effects[id] = effect;
    
    if(!in_array(vsk_Effects, this.b)) {
      vsk_Effects.push(this.b);
    }
    
    if(collision) {
      var i=0;
      for(i = 0; i < collision.length; i++)
        this.fx_halt(collision[i]);
    }
   
    this.fx_start();
  }
  
  return this;
};

/*****************************************************************************/
/** Function: fx_halt
  * Drop effect from node by it's id
  *
  * Parameters:
  *
  *	var id - unique effect id
  *	<bool silent> - if true neither the onhalt nor the sequence
  *	events are triggered
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.fx_halt = function(id, silent) {
  if(this.b && this.b.vsk_effects && this.b.vsk_effects[id]) {
    var E = this.b.vsk_effects[id];
    delete this.b.vsk_effects[id];
    if(E.onhalt && !silent)
      E.onhalt(this);
    if(E.sequence && !silent)
      E.sequence.loop();
    if(E._onhalt && !silent)
      E._onhalt(this);
  }
  return this;
};

/*****************************************************************************/
/** Method: fx_active
  * Check if an effect is currently active on the node by it's id
  *
  * Parameters:
  *
  *	var id - effect id to check
  *
  * Returns:
  *
  *	bool - true, if the effect is active on the node
  *	bool - false, if the effect is not active on the node
  */

VSK_Node.prototype.fx_active = function(id) {
  if(!this.b || !this.b.vsk_effects)
    return false;
  if(this.b.vsk_effects[id])
    return true;
  return false;
};

/******************************************************************************
 * V S K  F X  S E Q U E N C E ************************************************
 *****************************************************************************/
/** Class: VSK_FX_Sequence
  * class used to create effect sequences that can be looped
  *
  * Properties:
  *
  *	n - <VSK_Node>, the node this sequence is linked to
  *	body - *function*, holds the function the sequence in form of a
  *	function
  */

/*****************************************************************************/
/** Constructor: VSK_FX_Sequence
  *
  * Parameters:
  *
  *	VSK_Node n - the node this sequence is linked to
  */

function VSK_FX_Sequence(n) {
  this.n = n;
  this.loopMax = 0;
  this.loopCount = 0;
}

/*****************************************************************************/
/** Method: loop
  * executes the function stored in the <body> property of the sequence
  *
  * Parameters:
  *
  *	<int n> - loop n times
  */

VSK_FX_Sequence.prototype.loop = function(n) {
  if(typeof n != 'undefined') {
    this.loopMax = n;
    this.loopCount = 0;
  }
  
  if(this.loopMax && this.loopCount == this.loopMax)
    return;
  else if(this.loopMax)
    this.loopCount++;
  if(typeof this.body == 'function' && this.n)
    this.body(this.n);
};

/*****************************************************************************/
/** Method: halt
  * Halts the sequenced after it has been started by calling the <loop> method
  * The body property of the sequence is set to null and the original
  * body function is returned.
  * 
  * Returns:
  *
  *	function - the function that was pointed to by the body property
  */

VSK_FX_Sequence.prototype.halt = function(clearEffects) {
  this.n.fx_clear(clearEffects);
};
/*
Copyright (c) 2007 Stefan Pratter

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

/** File: vegui.sk.ani.fade.js
  *
  * Dependencies:
  *
  *	<vegui.sk.std.js>
  *	<vegui.sk.ani.js>
  *
  * Description:
  *
  *	Effect that allows you to smoothly fade a node into or out of few
  *	using the <VSK_Node::fade> method.
  *
  */
/** Class: VSK_Node */
/*****************************************************************************/
/** Function: fx_fade_in
  * fade in effect on node
  *
  * Parameters:
  *
  *     int n - time it takes until the node has faded in completly (ms)
  *     <int limit> - stop when a certain amount of transparency is reached
  *	(pcnt)
  *
  * Returns:
  *
  *	Object - the created event object
  */

VSK_Node.prototype.fx_fade_in = function(n, limit) {
  if(!this.b)
    return;

  var N = this.b;
  var t = (100 - this.t());

  if(!limit)
    var limit = 100;

  var E = {
    main : function() {
      var interval = t / (n / VSK_FX_INTERVAL);
      if(v(N).t() < limit)
        v(N).fade(v(N).t()+interval);
      else
        v(N).fx_halt('fade_in');
    }
  };

  this.fx_init('fade_in',E,['fade_out']);

  return E;
};

/*****************************************************************************/
/** Function: fx_fade_out
  * fade out effect on node
  *
  * Parameters:
  *
  *     int n - time it takes until the node has faded out completly (ms)
  *     <int limit> - stop when a certain amount of transparency is reached
  *	(pcnt)
  *
  * Returns:
  *
  *	Object - the created event object
  */

VSK_Node.prototype.fx_fade_out = function(n, limit) {
  if(!this.b)
    return;

  var N = this.b;
  var t = this.t();

  if(!limit)
    var limit = 1;
 
  var E = {
    main : function() {
      var interval = t / (n / VSK_FX_INTERVAL);
      if(v(N).t() > limit)
        v(N).fade(v(N).t()-interval);
      else
        v(N).fx_halt('fade_out');
    }
  };

  this.fx_init('fade_out',E,['fade_in']);
  
  return E;
};

/*
Copyright (c) 2007 Stefan Pratter

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

/******************************************************************************
 * G L O B A L S **************************************************************
 *****************************************************************************/
/** File: vegui.sk.ani.morph.js
  *
  * Dependencies:
  *
  *	<vegui.sk.std.js>
  *	<vegui.sk.ani.js>
  */

/******************************************************************************
 * E X T E N D I N G  V S K  N O D E ******************************************
 *****************************************************************************/
/** Class: VSK_Node */

/*****************************************************************************/
/** Method: fx_morph
  * The morph effect lets you grow and move a node in a smooth animation that
  * can be usefull for popup effects or object sliding
  *
  * Parameters:
  *
  *	<int w> - target width
  *	<int h> - target height
  *	<int x> - target position on x axis
  *	<int y> - target position on y axis
  *	int time - effect time (ms)
  *
  * Ommitting arguments:
  *
  *	You can ommit any of the arguments by submitting them as null, so it
  *	is possible to only change the size or to only move a node as well.
  *
  * Returns:
  *
  *	Object - the created effect object
  *
  */

VSK_Node.prototype.fx_morph = function(w,h,x,y,t) {
  
  if(!this.b)
    return {};

  var N = this;

  var E = {
    type_w : (w < this.w()),
    type_h : (h < this.h()),
    type_x : (x < this.x()),
    type_y : (y < this.y()),
    w : w,
    h : h,
    x : x,
    y : y,
    oW : this.w(),
    oH : this.h(),
    oX : this.x(),
    oY : this.y(),
    iW : 0,
    iH : 0,
    iX : 0,
    iY : 0,
    interval : (t / VSK_FX_INTERVAL),
    main : function() {
      
      this.iW += (Math.abs(this.w - this.oW) / this.interval);
      this.iH += (Math.abs(this.h - this.oH) / this.interval);
      
      /* check if the size is at the targeted site yet */

      var w = (N.w() == this.w);
      var h = (N.h() == this.h);
      
      var _iw = Math.floor(this.iW);
      var _ih = Math.floor(this.iH);

      /* if not, resize node */

      if((!w && this.iW>=1) || (!h && this.iH>=1)) {
        
	var _uw = (!w ? (!this.type_w ? N.w()+_iw : N.w()-_iw) : null);
	var _uh = (!h ? (!this.type_h ? N.h()+_ih : N.h()-_ih) : null);
	
        N.resize(
	  (_uw > -1 ? _uw : 1), (_uh > -1 ? _uh : 1)
	);
      }

      if(this.iW >= 1)
        this.iW = (this.iW - _iw);
      if(this.iH >= 1)
        this.iH = (this.iH - _ih);
     
      /* possible size correction */
     
      var _w = (!this.type_w ? (N.w() > this.w) : (N.w() < this.w));
      var _h = (!this.type_h ? (N.h() > this.h) : (N.h() < this.h));

      if(_w || _h) {
        N.resize(
	  (_w ? this.w : null), (_h ? this.h : null)
	);
      }

      /* 
       * Move node
       */

      if(this.x !== null && this.y !== null) {

      this.iX += (Math.abs(this.x - this.oX) / this.interval);
      this.iY += (Math.abs(this.y - this.oY) / this.interval);

      var _ix = Math.floor(this.iX);
      var _iy = Math.floor(this.iY);

      /* check if node is positioned at targeted position yet */

      var x = (N.x() == this.x);
      var y = (N.y() == this.y);

      /* if not, move node */

      if((!x && this.iX>=1) || (!y && this.iY>=1)) {
        N.move(
	  (!x ? (this.x > N.x() ? N.x()+_ix : N.x()-_ix) : null),
	  (!y ? (this.y > N.y() ? N.y()+_iy : N.y()-_iy) : null)
	);
      }

      if(this.iX >= 1)
        this.iX -= _ix;
      
      if(this.iY >= 1)
        this.iY -= _iy;

      /* check if node is close to its target position, if it is
       * move it there (position correction)
       */

      var _x = (Math.abs(N.x() - this.x) <= (Math.abs(this.oX - this.x) / this.interval));
      var _y = (Math.abs(N.y() - this.y) <= (Math.abs(this.oY - this.y) / this.interval));

      if(_x || _y) {
        N.move(
	  (_x ? this.x : null),
	  (_y ? this.y : null)
	);
      }
      } else {
        var x = true, y = true;
      }
      
      if(w && h && x && y)
        N.fx_halt('morph');
      
    }

  };

  this.fx_init('morph',E);

  return E;
  
};
/*
Copyright (c) 2007 Stefan Pratter

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

/******************************************************************************
 * G L O B A L S **************************************************************
 *****************************************************************************/
/** File: vegui.sk.cookie.js
  *
  * Dependencies:
  *
  *	none
  */

/*****************************************************************************/
/** Function: vsk_cookie_set
  * Sets a cookie
  *
  * Parameters:
  *
  *	string name - variable name to set
  *	variable value - value of cookie variable
  *	<int time> - validity time of variable (ms)
  *	<string path> - path component of the cookie variable
  *
  * See also:
  *
  *	<vsk_cookie_get>, <vsk_cookie_unset>, <vsk_cookie_list>
  */

function vsk_cookie_set(name, value, time, path) {
  if(!name || typeof value == 'undefined')
    return;
 
  if(time) {
    var d = new Date();
    d.setTime(d.getTime()+time);
    var v = '; expires='+d.toGMTString();
  } else
    var v = '';

  if(!path)
    var path = '/';

  document.cookie = name+'='+value+v+'; path='+path;
}

/*****************************************************************************/
/** Function: vsk_cookie_get
  * Return value of a cookie variable
  *
  * Parameters:
  *
  *	string name - variable name
  *
  * Returns:
  *
  *	variable - value of the requested variable
  *	null - if no cookie variable by the requested name was found
  *
  * See also:
  *
  *	<vsk_cookie_set>, <vsk_cookie_list>
  */

function vsk_cookie_get(name) {
  var name = name + '=', i, v; 
  var values = document.cookie.split(';');
  for(i=0; i<values.length;++i){
    v = values[i];
    while(v.charAt(0) == ' ') 
      v = v.substring(1, v.length);
    if(v.indexOf(name) == 0)
      return v.substring(name.length, v.length);
  }
  return null;
}

/*****************************************************************************/
/** Function: vsk_cookie_list
  * Creates and returns a list of all the cookies in the document in object
  * form
  *
  * Returns:
  *
  *	Object - object holding cookie key : value pairs
  *
  * See also:
  *
  *	<vsk_cookie_get>
  */

function vsk_cookie_list() {
  var values = document.cookie.split(';'),i,v,p;
  var list = {};
  
  for(i = 0; i < values.length; i++) {
    p = values[i].split('=');
    list[p[0]] = p[1].substring(0,p[1].length);
  }
  return list;
}

/*****************************************************************************/
/** Function: vsk_cookie_unset
  * Delete a cookie variable
  *
  * Parameters:
  *
  *	string name - name of the cookie variable you want to delete
  */

function vsk_cookie_unset(name) {
  vsk_cookie_set(name,'',-1000);
}
/*
Copyright (c) 2007 Stefan Pratter

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

/******************************************************************************
 * G L O B A L S **************************************************************
 *****************************************************************************/
/** File: vegui.sk.tooltip.js
  *
  * Dependencies:
  *
  *	<vegui.sk.std.js>
  *	<vegui.sk.ani.js>
  *	<vegui.sk.ani.fade.js>
  *	<vegui.sk.ani.morph.js>
  */

/** Constant: VSK_TTIP_FX_TIME
  * Effect time for the morph or fade effects on the tooltip (ms)
  */

var VSK_TTIP_FX_TIME = 200;

/** Constant: VSK_TTIP_MAX_WIDTH
  * Maximum width of the tooltip
  */
  
var VSK_TTIP_MAX_WIDTH = 200;

/** Constant: VSK_TTIP_FX_TYPE
  * Effect type to use to blend the tooltip in and out
  *
  * Possible Values:
  *
  *	'fade' - tooltip is faded in/out
  *	'morph' - tooltip grows/shrinks
  *	null - no effect
  */

var VSK_TTIP_FX_TYPE = 'fade';

/** Constant: VSK_TTIP_USE_SHADOW
  * If set to true then the shadow effect <vegui.sk.ani.shadow.js> will
  * be used (if the library has been loaded), default: false
  */

var VSK_TTIP_USE_SHADOW = false;

/** Constant: VSK_TTIP_SHADOW_TRANSPARENCY
  * Defines the transparency value of the tooltip shadow, default: 15
  */

var VSK_TTIP_SHADOW_TRANSPARENCY = 15;

/** Constant: VSK_TTIP_SHADOW_OFFSET_X
  * Defines the shadow offset on the x axis, default: 5
  */

var VSK_TTIP_SHADOW_OFFSET_X = 5;

/** Constant: VSK_TTIP_SHADOW_OFFSET_Y
  * Defines the shadow offset on the y axis, default: 5
  */

var VSK_TTIP_SHADOW_OFFSET_Y = 5;

/** Constant: VSK_TTIP_SHADOW_COLOR
  * Defines the shadow color, default: '#000'
  */

var VSK_TTIP_SHADOW_COLOR = '#000';

/** Constant: VSK_TTIP_NODE
  * Can be set to point to a per-pepared node that will be used to
  * clone the tooltip node from
  */

var VSK_TTIP_NODE = null;

/** Constant: VSK_TTIP
  * Object that defines which node types are scanned for
  * the vsk_ttip attribute. span,a and p are activated by
  * default.
  *
  * To enable any addinional node types simply create a property
  * in the VSK_TTIP object by their name and set it to
  * true
  *
  * (start code)
  * VSK_TTIP.td = true;
  * (end)
  */

var VSK_TTIP = {
  span : true,
  a : true,
  p : true
};

/******************************************************************************
 * E X T E N D  V S K  N O D E ************************************************
 *****************************************************************************/
/** Class: VSK_Node */

/*****************************************************************************/
/** Method: ttip_show
  * Creates and shows a tooltip */ 

VSK_Node.prototype.ttip_show = function(text) {
  
  if(!this.b.ttipNode) {
    if(VSK_TTIP_NODE)
      var t = v(VSK_TTIP_NODE.cloneNode(1));
    else
      var t = v(vsk_h('div'));
    
    t.s.display = 'inline';
    t.s.position = 'absolute';
    t.s.zIndex = 100000;
    t.b.className = 'vsk_tooltip';
    t.b.innerHTML = text;
    t.dock(document.body);
    
    if(t.w() > VSK_TTIP_MAX_WIDTH)
      t.resize(VSK_TTIP_MAX_WIDTH);
   
    if(VSK_TTIP_FX_TYPE == 'fade') {
      t.fade(1).fx_fade_in(VSK_TTIP_FX_TIME);
    } else if(VSK_TTIP_FX_TYPE == 'morph') {
      t.s.padding = '0px';
      var h = t.h(1), w = t.w(1), n = t.b;
      
      if(w > VSK_TTIP_MAX_WIDTH)
        w = VSK_TTIP_MAX_WIDTH;
	
      t.clear().resize(1,1).fx_morph(w,h,null,null,VSK_TTIP_FX_TIME).onhalt = 
      function() {
        n.innerHTML = text;
      };
      t.s.padding = '';
    }
    
    this.b.ttipNode = t.b;
    
    /* add shadow effect to tooltip if the library has been loaded
     * and the VSK_TTIP_USE_SHADOW global is set to true
     */
    
    if(t.fx_shadow && VSK_TTIP_USE_SHADOW) {
      t.fx_shadow(
        VSK_TTIP_SHADOW_TRANSPARENCY,
	VSK_TTIP_SHADOW_COLOR,
	VSK_TTIP_SHADOW_OFFSET_X,
	VSK_TTIP_SHADOW_OFFSET_Y
      );
    }

  
  } else
    var t = v(this.b.ttipNode);

  t.move(vskX + 10, vskY + 10);
  
};

/*****************************************************************************/
/** Method: ttip_hide
  * Destroys the node's tooltip
  */

VSK_Node.prototype.ttip_hide = function() {
  if(!this.b || !this.b.ttipNode)
    return;

  if(VSK_TTIP_FX_TYPE == 'fade') {
    
    var t = new Date().getTime();
    var id = 'vsk_ttip_'+t;
    this.b.ttipNode.id = id;
    var n = V(id);
    
    n.fx_fade_out(VSK_TTIP_FX_TIME).onhalt = function() {
      V(id).undock();
    };

  } else
    v(this.b.ttipNode).undock();
  this.b.ttipNode = null;
};

/******************************************************************************
 * I N I T ********************************************************************
 *****************************************************************************/

v(window).event_add('load', function() {
  
  var t, n, i, e, ttip;

  for(t in VSK_TTIP) {
    if(!VSK_TTIP[t])
      continue;
    e = document.getElementsByTagName(t);
    
    for(i = 0; i < e.length; i++) {
      
      n = e[i];
      
      if((ttip = n.getAttribute('vsk_ttip'))) {
	__vsk_ttip_event_show(v(n));
        __vsk_ttip_event_hide(v(n));
      }
    }
  }
  
});

/*****************************************************************************/
/** Functions to set event handling, because IE's attachEvent sucks */

function __vsk_ttip_event_hide(n) {
  n.event_add('mouseout', function(e) {
    var rel = vsk_rel_target(e ? e : event);
    if(!v(rel).has_parent(n.b) && n.b != rel)
      n.ttip_hide();				
  });
}

function __vsk_ttip_event_show(n) {
  n.event_add('mousemove', function(e) {
    vsk_get_mouse((e ? e : event));
    n.ttip_show(n.b.getAttribute('vsk_ttip'));
  });
}
/******************************************************************************
 * G L O B A L S **************************************************************
 *****************************************************************************/
/** File: vegui.sk.window.js
  *
  * Dependencies: 
  *
  *	none
  */

if(document.documentElement && document.documentElement.clientHeight)
  var isIEStrict = true;
else
  var isIEStrict = false;

/** Object: window */

/*****************************************************************************/
/** Function: vsk_iw
  * Returns the inner width of the document (cross browser)
  */

vsk_iw = function() {
  if(typeof window.innerWidth != 'undefined')
    return window.innerWidth;
  if(isIEStrict)
    return document.documentElement.clientWidth;
  else 
    return document.body.clientWidth;
};

/*****************************************************************************/
/** Function: vsk_ih
  * Returns the inner height of the document (cross browser)
  */

vsk_ih = function() {
  if(typeof window.innerHeight != 'undefined')
    return window.innerHeight;
  if(isIEStrict)
    return document.documentElement.clientHeight;
  else
    return document.body.clientHeight;
};

/*****************************************************************************/
/** Function: vsk_ox
  * Returns the x offset of the document (cross browser)
  */

vsk_ox = function() {
  if(typeof window.pageXOffset != 'undefined')
    return window.pageXOffset;
  if(isIEStrict)
    return document.documentElement.scrollLeft;
  else
    return document.body.scrollLeft;
};

/*****************************************************************************/
/** Function: vsk_oy
  * Returns the y offset of the document (cross browser)
  */

vsk_oy = function() {
  if(typeof window.pageYOffset != 'undefined')
    return window.pageYOffset;
  if(isIEStrict)
    return document.documentElement.scrollTop;
  else
    return document.body.scrollTop;
};

/******************************************************************************
 * G L O B A L S **************************************************************
 *****************************************************************************/
/** File: vegui.sk.ani.shadow.js
  * Allows you to add a static shadow effect to any HTML node
  *
  * Dependencies:
  *
  *	<vegui.sk.std.js>, <vegui.sk.ani.js>
  */

/******************************************************************************
 * E X T E N D I N G  V S K  N O D E ******************************************
 *****************************************************************************/
/** Class: VSK_Node */

/*****************************************************************************/
/** Method: fx_shadow_adjust
  * Adjust the node's shadow node to the node's position and size
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.fx_shadow_adjust = function() {
  if(!this.b || !this.fx_active('shadow'))
    return this;
  
  var E = this.b.vsk_effects['shadow'];
  var n = v(E.node);
  
  n.resize(this.w(1), this.h(1)).move(this.x() + E.oX, this.y() + E.oY);
  
  if(!n.b.parentNode) {
    n.set_pos('absolute', this.s.zIndex-1);
    n.hide(1).dock(this.b.parentNode).hide(0);
  }

  n.hide(this.v()^1);

  return this;
};

/*****************************************************************************/
/** Method: fx_shadow
  * Add shadow effect to the node
  *
  * Effect Id:
  *
  *	'shadow'
  *
  * Parameters:
  *
  *	int t - transparency value (percent)
  *	string c - color string (ie. '#000000' or 'black' for black)
  *	int oX - offset X 
  *	int oY - offset Y
  *
  * Returns:
  *
  *	Object - the created event object
  */

VSK_Node.prototype.fx_shadow = function(t, c, oX, oY) {
  if(!this.b)
    return {};
  
  var n = this.b;
  
  if(!this.s.zIndex)
    this.s.zIndex = 1;

  this.vsk_event_add('move', function(b) { v(b).fx_shadow_adjust(); });
  this.vsk_event_add('resize', function(b) { v(b).fx_shadow_adjust(); });
  this.vsk_event_add('undock', function(b) { v(b).fx_halt('shadow'); });
  this.vsk_event_add('hide', function(b) { v(b).fx_shadow_adjust(); });

  var E = {
    oX : oX,
    oY : oY,
    t : t,
    c : c,
    node : vsk_h('div'),
    main : function() {},
    _onhalt : function() {
      v(this.node).undock();
    }
  };

  v(E.node).fade(t).s.backgroundColor = c;
  
  this.fx_init('shadow', E);
  this.fx_shadow_adjust();
  
  return E;
};
/******************************************************************************
 * G L O B A L S **************************************************************
 *****************************************************************************/
/** File: vegui.sk.validate.js
  * Functions for client-side user input validation
  */

/*****************************************************************************/
/** Function: vsk_input_validate_required
  * Validate required user input
  *
  * Parameters:
  *
  *	Node input - pointer to form element
  *
  * Returns:
  *
  *	bool - true, if valid
  *	bool - false, if invalid
  */

function vsk_input_validate_required(input) {
  if(!input)
    return false;
  n = input.nodeName.toLowerCase();
  if(n == 'input' || n == 'textarea')
    return (input.value !== '');
  else if(input.type == 'select') 
    return (input.selectedIndex !== null);
}

/*****************************************************************************/
/** Function: vsk_input_validate_numeric
  * Validate user input to be a numeric value
  *
  * Parameters:
  *
  *	string input - string to validate
  *
  * Returns:
  *
  *	bool - true, if valid
  *	bool - false, if invalid
  */

function vsk_input_validate_numeric(input) {
  return !(new String(input).match(/[^\d-]/));
}

/*****************************************************************************/
/** Function: vsk_input_validate_email
  * Validate user input to be a valid email address
  *
  * Parameters:
  *
  *	String input - string to validate
  *
  * Returns:
  *
  *	bool - true, if valid
  *	bool - false, if invalid
  */

function vsk_input_validate_email(input) {
  return (new String(input).match(/\b[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b/i));
}

/*****************************************************************************/
/** Function: vsk_input_validate_url
  * Validate user input to be a valid URL
  *
  * Parameters:
  *
  *	string input - string to validate
  *
  * Returns:
  *
  *	bool - true, if valid
  *	bool - false, if invalid
  */

function vsk_input_validate_url(input) {
  return (new String(input).match(/^(ftp|http|https|mailto|file):\/\/([\w\d][\w\d\$\_\.\+\!\*\(\)\,\;\/\?\:\@\&\~\=\-]+)(:(\d+))?(\/[^ ]*)?$/i));
}
/******************************************************************************
 * G L O B A L S **************************************************************
 *****************************************************************************/
/** File: vegui.sk.formcheck.js
  * Allows you to have client side validation with error messages on 
  * HTML forms
  *
  * Dependencies:
  *
  *	<vegui.sk.std.js>, <vegui.sk.validate.js>
  *
  * Optional Dependencies for full functionality:
  *
  *	<vegui.sk.ani.js>, <vegui.sk.ani.fade.js> if you want to fade in
  *	error messages, *THIS FEATURE DOES NOT WORK IN INTERNET EXPLORER*
  *
  * Valid HTML attributes for input fields in a form:
  *
  *	vsk_required - validation on existing value 
  *	vsk_numeric - validation that value is a number
  *	vsk_email - validation that value is a valid email address
  *	vsk_url - validation that value is a valid URL
  */

/** Global: VSK_FORMCHECK_USE_FX_FADE
  * If set to true the script will try to use the fx_fade_in effect
  * provided by <vegui.sk.ani.fade.js> to fade in any error messages.
  * (true by default)
  */

var VSK_FORMCHECK_USE_FX_FADE = 1; 

/** Global: VSK_FORMCHECK_FADE_TIME
  * if <VSK_FORMCHECK_USE_FX_FADE> is true you can set the effect
  * time over this variable (ms, default: 500)
  */

var VSK_FORMCHECK_FADE_TIME = 300;

/** Global: VSK_FORMCHECK_INIT
  * Object holding the various validation types
  */

var VSK_FORMCHECK_INIT = {
  vsk_required : {
    msg : 'Input/Selection is required for this field',
    func : vsk_input_validate_required,
    useField : true
  },
  vsk_numeric : {
    msg : 'Input needs to be numeric for this field',
    func : vsk_input_validate_numeric
  },
  vsk_email : { 
    msg : 'This email-address seems to be invalid',
    func : vsk_input_validate_email
  },
  vsk_url : {
    msg : 'This URL seems to be invalid',
    func : vsk_input_validate_url
  }
};

/** Global: VSK_FORMCHECK_ERROR_CSS
  * The css class to use for the error message (span)
  */

var VSK_FORMCHECK_ERROR_CSS = 'vsk_frmchk_error';

/** Global: VSK_FORMCHECK_ERROR_ELEMENT_CSS
  * The css class to use for a form element that was invalid
  */

var VSK_FORMCHECK_ERROR_ELEMENT_CSS = 'vsk_frmchk_error_element';

/*****************************************************************************/
/** Function: vsk_formcheck
  * Validate every input field depending on the attributes set on it. 
  *
  * Parameters:
  *
  *	Node form - form element
  *	string align - general alignment of error messages to their element
  *	, only relevent when vsk_error attribute is not submitted
  *
  * Valid Alignment Strings:
  *
  *	't' - on top of the error element
  *	'b' - under the error element
  */

function vsk_formcheck(form, align) {
  var f,i,rv=true;
  f = v(form); 
  if(!align)
    var align = 'r';
  var inputs = f.b.getElementsByTagName('input');
  var textareas = f.b.getElementsByTagName('textarea');
  var selects = f.b.getElementsByTagName('select');  

  for(i = 0; i < inputs.length; i++) {
    if(!vsk_inputcheck(inputs[i], align))
      rv = false;
  }
  return rv;
}

function vsk_inputcheck(input, align) {
  if(!input)
    return false;
  var rv = true, msg = [], i, iN, g, val;

  if((iN = input.getAttribute('vsk_error')))
    iN = V(iN);
 
  for(i in VSK_FORMCHECK_INIT) {
    if(input.getAttribute(i)) {
      g = VSK_FORMCHECK_INIT[i];
      val = (input.nodeName.toLowerCase() == 'select' ? input.selectedIndex : input.value);
      
      if(!g.useField && input.value === '')
        continue;
      
      if(!g.func((g.useField ? input : val))) {
        msg.push(VSK_FORMCHECK_INIT[i].msg);
	rv = false;
      }
    }
  }
 
  if(!rv) {
    
    /* process messages */

    if(!input.vskValError) {
      var m = input.vskValError = vsk_h('div', VSK_FORMCHECK_ERROR_CSS);
      if(!iN || !iN.b) {
        switch(align) {
          case 't': v(input).html_ib(m); break;
  	  case 'b': v(input).html_ia(m); break;
        }
      } else 
        v(m).dock(iN.b);
    } else {
      var m = input.vskValError;
      v(m).clear();
    }
    for(i = 0; i < msg.length; i++) { 
      var d = v(vsk_h('div'));
      v(m).html_a(d.html_a(vsk_t(msg[i])));
    }
    if(v(m).fx_fade_in && VSK_FORMCHECK_USE_FX_FADE) { 
      v(m).fade(1).fx_fade_in(VSK_FORMCHECK_FADE_TIME);
    }

    if(input.className !== VSK_FORMCHECK_ERROR_ELEMENT_CSS)
      input.oldClass = input.className;
    input.className = VSK_FORMCHECK_ERROR_ELEMENT_CSS;
  } else if(input.oldClass){
    input.className = input.oldClass;
    if(input.vskValError) {
      v(input.vskValError).undock();
      input.vskValError = null;
    }
  }
  return rv;
  
}
/*
 
 Copyright (c) 2005,2006 Stefan Pratter

 Permission is hereby granted, free of charge, to any person
 obtaining a copy of this software and associated documentation
 files (the "Software"), to deal in the Software without
 restriction, including without limitation the rights to use,
 copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the
 Software is furnished to do so, subject to the following
 conditions:

 The above copyright notice and this permission notice shall be
 included in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 
 */

/*
 * Allows Client - Server communication via XMLHttpRequest
 */

/** Constant: VUI_URL
  * allows you do specify which domain to use for all requests sent
  * with the bridge, default: ''
  */

var VUI_URL = '';

/******************************************************************************
 * V E G U I  R E Q U E S T ***************************************************
 *****************************************************************************/
/** Class: VegUIRequest
  *
  * VegUI xml request object
  *
  * Properties: Object Properties
  *
  *	timeCreation - *int*, time of creation
  *	timeSend - *int*, time it took to send and get a request
  *	request - *XMLHttpRequest*, the xml http request object
  *	toElement - *VegUIElement*, request belongs to this element
  *	process - *function*, if set this function will be executed when
  *	the request has been responded to by the server
  *	id - *int*, unique request id
  */

/*****************************************************************************/
/** Constructor: VegUIRequest
  *
  * *constructor*
  *
  * Parameters:
  *
  *	XMLHttpRequest req - the xml http request object
  *	int id - the unique request id
  *	<VegUIElement toElement> - flags this request as belong to the
  *	submitted element
  */

function VegUIRequest(req, id, toElement) {
  this.timeCreation = new Date().getTime();
  this.timeSend = null;
  this.request = req;
  this.toElement = toElement;
  this.process =  null;
  this.id = id;
}

/******************************************************************************
 * V E G U I  B R I D G E *****************************************************
 *****************************************************************************/
/** Class: VegUIBridge
  *
  * Allows client - server communication
  *
  * Properties: Object Properties
  *
  *	maxSendTime - *int*, maximum time a request can take before timing out
  *	maxTimeouts - *int*, maximum number of timeouts before <onmaxtimeouts>
  *	is called
  *	conTimeouts - *int*, current timeouts in a row
  *	sendNum - *int*, number of requests sent
  *	timeoutNum - *int*, total number of timeouts
  *	successNum - *int*, total number of successful requests
  *	PTimer - *Interval*, the interval object that polls timeouts
  *	denyRequests - *bool', if true no requests can be sent
  *	resend - *bool*, if true failed requests will be resent
  *	Request, R - *Array*, holds all active requests
  */


function VegUIBridge() {

  this.R = this.Request = [];

  this.maxSendTime = 5000;
  this.maxTimeouts = 10;
  this.conTimeouts = 0;
  this.sendNum = 0;
  this.timeoutNum = 0;
  this.successNum = 0;
  this.PTimer = null;
  this.denyRequests = false;
  this.resend = true;
  
  /***************************************************************************/
  /** Method: cleanup
    *
    * Removes a request from the list
    *
    * Parameters:
    *
    *	VegUIRequest vreq - request to be removed
    *
    */
   
  this.cleanup = function(vreq) {
    this.R[vreq.id].request.onreadystatechange = function() { return; };
    delete this.R[vreq.id];
  };
 
  /****************************************************************************/
  /** Method: execute
    *
    * This function will be called on successful response to request if the 
    * <VegUIRequest>'s pFunc property is not set. Be aware that you
    * may overwrite the execute methid with your own by simply redefining
    * it
    * 
    * Parameters:
    *
    *	VegUIRequest vreq - the request that was successful
    *
    * Returns:
    *
    *	bool - true
    */

  this.execute = function(vreq) { 
    return true; 
  };
 
  /***************************************************************************/
  /** Method: new_request
    *
    * Spawns a new XMLHttpRequest object and returns it in the form of
    * a <VegUIRequest> object
    *
    * Parameters:
    *
    *	<VegUIElement toElement> - if set the request will be flagged to
    *	belong to the submitted element
    *
    */

  this.new_request = function(toElement) {
    var req;
    if(window.XMLHttpRequest)
      req = new XMLHttpRequest();
    else {
      if(window.ActiveXObject) 
        req = new ActiveXObject('Msxml2.XMLHTTP');
      else
        req = new ActiveXObject('Microsoft.XMLHTTP');
    }

    if(!req)
      return null;

    var vreq = new VegUIRequest(req, this.valid_id(), toElement);
    this.R[vreq.id] = vreq;
    
    return this.R[vreq.id];
  }; 
  
  /***************************************************************************/
  /** Functions: Event Handlers
    *
    *	onmaxtimeouts - triggered when the maximum number of timeouts is
    *	reched
    *	ontimeout - triggered everytime a request times out, submits the
    *	timed out request as a parameter
    */
  
  this.onmaxtimeouts = function() { 
    alert('Lost connection to the server'); 
    return true; 
  };
  this.ontimeout = function(vreq) { return true; };
  
  /***************************************************************************/
  /** Method: poll_timeouts
    *
    * Polls the Request array for any timed out requests and handles
    * them arcordingly. May call <onmaxtimeouts> and <ontimeout>
    */

  this.poll_timeouts = function() {
    var r;
    var time = new Date().getTime();
    for(r in this.R) {
      if(time - this.R[r].timeSend > this.maxSendTime) {
        this.ontimeout(this.R[r]);	
	this.R[r].request.abort();
	
	if(this.resend)
	  this.send(this.R[r].url, this.R[r].para, this.R[r].method);
	
	this.cleanup(this.R[r]);
	this.conTimeouts++;
	this.timeoutNum++;
      }
    }
    if(this.conTimeouts >= this.maxTimeouts)
      this.onmaxtimeouts();
  }; 
 
  /***************************************************************************/
  /** Method: process_request
    *
    * When a request gets a response from the server then it will go through
    * this function where it will determine if it was a successful request
    * or not
    *
    * Parameters:
    *
    *	VegUIRequest vreq - the request object 
    */

  this.process_request = function(vreq) {
    var req = vreq.request;
    if(req.readyState == 4) {
      if(req.status == 200) {
        this.successNum++;
        this.conTimeouts = 0;
	if(!vreq.process)
	  this.execute(vreq);
        else
	  vreq.process();
      } else {
	this.conTimeouts++;
	this.ontimeout(vreq);
      }
      this.cleanup(vreq);
    }
  };
  
  /***************************************************************************/
  /** Method: send
    *
    * send a request to the server
    *
    * Parameters:
    *
    *	string url - url or relative path to send the request to
    *	<string para> - url parameter string
    *	<string method> - method to use
    *	<function pFunc> - custom process function that will be executed
    *	when the request was returned successfully
    *	<bool sync> - if true the request will be async to the execution
    *	of the script, allowing the execution to continue while the
    *	request is sent. True by default.
    * 
    * See also:
    *
    *	<process>
    *
    */

  this.send = function(url, para, method, pFunc, sync) {

    if(this.denyRequests)
      return null;
  
    var req, vreq, Bridge = this;
    
    if( !(vreq = this.new_request()) ) {
      alert('VegUIBridge: Could not create XMLHttpRequest Object');
      return;
    }

    vreq.timeSend = new Date().getTime();

    vreq.url = url;
    vreq.para = para;
    vreq.method = method;
    vreq.process = pFunc;
    
    var req = vreq.request;
    
    var method = method ? method : 'GET';
    var url = VUI_URL+url+(method=='GET' ? '?'+para : '');
    req.onreadystatechange = function() { Bridge.process_request(vreq); };
    
    if(sync)
      req.open(method, url);
    else
      req.open(method, url, true);

    if(method.toUpperCase() == 'POST') {
      req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 
      req.send(para);
    } else
      req.send(null);

    this.sendNum++;

  };

  /***************************************************************************/
  /** Method: valid_id
    *
    * Returns:
    *
    *	int - valid request id
    */

  this.valid_id = function() {
    var id = (Math.round(Math.random()*9999)+1);
    while(this.R[id])
      id = (Math.round(Math.random()*9999)+1);
    return id;
  };
  
}


/******************************************************************************
 * G L O B A L S **************************************************************
 *****************************************************************************/
 /** File: vegui.sk.pulsatingmenu.js
   *
   * Integrates a navigation menu with animated menu points
   *
   * Dependencies:
   *
   *	<vegui.sk.std.js>, <vegui.sk.ani.js>, <vegui.sk.ani.morph.js>
   *
   */

/** Cosntant: VSK_PMNU_FX_TIME
  * effect time of the growth / shrink effect (ms)
  * , default = 150 ms
  */

var VSK_PMNU_FX_TIME = 150;

/*****************************************************************************/
/** Function: pmnu_init
  * Initialize one or more pulsating menus
  *
  * Parameters:
  *
  *	int smallW - the width of the small version of the icon (pixels)
  *	int smallH - the height of the small version of the icon (pixels)
  *	int bigW - the width of the big version of the icon (pixels)
  *	int bigH - the height of the big version of the icon (pixels)
  * 	String id <...> - node ids of the various menu nodes you want to initialize
  *
  */

function pmnu_init(smallW, smallH, bigW, bigH, id) {
  var i,menu,n,img;
  
  if(!(menu = V(id)))
    return;

  var nodes = menu.b.getElementsByTagName('td');
  
  for(i = 0; i < nodes.length; i++) {
    n = v(nodes[i]);
    n.s.verticalAlign = 'middle';
    n.s.textAlign = 'center';
    n.s.padding = '0px';
    n.s.cursor = 'pointer';
    img = v(n.b.getElementsByTagName('img')[0]);
    
    /* make sure to preload the image 2 */
    
    var preload = new Image();
    preload.src = img.b.src.replace(/1\.([\w\d]+)$/g,"2.$1");

    n.b.onmouseover = function(e) {
      var img = this.getElementsByTagName('img')[0];
      v(img).fx_morph(bigW, bigH, null, null, VSK_PMNU_FX_TIME).onhalt = function() {
        v(img).b.src = v(img).b.src.replace(/1\.([\w\d]+)$/g,"2.$1");
      };
    };
    n.b.onmouseout = function(e) {
      if(v(vsk_rel_target((e || event))).has_parent(this))
        return true;
      var img = this.getElementsByTagName('img')[0];
      v(img).fx_morph(smallW, smallH, null, null, VSK_PMNU_FX_TIME).onhalt = function() {
        v(img).b.src = v(img).b.src.replace(/2\.([\w\d]+)$/g,"1.$1");
      }
    };
    img.resize(smallW, smallH);
    
    n.resize(null, bigH);
  }
  
}
/******************************************************************************
 * G L O B A L S **************************************************************
 *****************************************************************************/
 /** File: vegui.sk.dropdownmenu.js
   *
   * Allows you to integrate drop down navigation menus into your site
   * easily
   *
   * Dependencies:
   *
   *	<vegui.sk.std.js>
   *
   * Optional Depencencies for full functionality:
   *
   *	<vegui.sk.ani.js>, <vegui.sk.ani.morph.js>, <vegui.sk.ani.fade.js>,
   *	<vegui.sk.ani.shadow.js>
   *
   */

var VSK_MENU_TIMER = 0;

/** Constant: VSK_MENU_CLOSE_TIME
  * Time it takes for a menu to close after the mouse pointer has left it (ms)
  * , default = 1000 ms (1 sec)
  */

var VSK_MENU_CLOSE_TIME = 1000;

/*****************************************************************************/
/** Function: ddmnu_init
  * Initialize one or more drop down menues by submitting one or more node
  * ids to the function.
  *
  * Parameters:
  *
  *	array menus - array holding menu node ids of menus that you want
  *	to initialize
  *	int nMarg - margin between nested menus and their parent menu (px)
  *	<string useFx> - define which effect to use for menu opening
  *	<int fxTime> - time of the menu opening effect (ms)
  *	<bool shad> - if true the shadow affect (<vegui.sk.ani.shadow.js>) will
  *	be applied to each menu
  *	<int shadX> - x offset of the shadow (px)
  *	<int shadY> - y offset of the shadow (px)
  *	<string shadC> - color of the shadow (valid css color string)
  *	<int shadT> - shadow transparency (1-100)
  *
  * useFX values:
  *
  *	'fade' - fade effect of <vegui.sk.ani.fade.js> is used
  *	'morph' - morph effect of <vegui.sk.ani.morph.js> is used
  *	null - no effect us used
  *
  */

function ddmnu_init(menus, nMarg, useFx, fxTime, shad, shadX, shadY, shadC, shadT) {
  var i,m,O,o,n;
  for(i = 0; i < menus.length; i++) {
    
    if(!(m = V(menus[i])))
      continue;


    /* make sure the menu starts out hidden */

    m.s.visibility = 'hidden';
    m.s.display = 'inline';
    m.set_pos('absolute', 1000);
    m.b.vskMenuFriends = menus;

    /* set up the onmouseout event to trigger the closing of the menu */

    m.b.onmouseout = function(e) {
      var m = v(this), rt = vsk_rel_target(e || event);
      if(v(rt).has_parent(m.b) || rt == this)
        return;
      m.b.vskMenuFocus = false;
      if(this.vskParentMenu && (rt == this.vskParentMenu.b || v(rt).has_parent(this.vskParentMenu.b)))
        this.vskParentMenu.b.vskMenuFocus = true;
      if(this.vskOpenMenu && (v(rt).has_parent(this.vskOpenMenu.b) || rt == this.vskOpenMenu.b))
        return;
      VSK_MENU_TIMER = clearTimeout(VSK_MENU_TIMER);
      VSK_MENU_TIMER = setTimeout(function() {m.ddmenu_close()}, 1000);
    };

    m.b.onmouseover = function(e) {
      var m = v(this);
      m.b.vskMenuFocus = true;
    };
    
    m.b.vskUseFx = useFx;
    m.b.vskFxTime = fxTime;
    m.dock(document.body);

    /* apply shadow if needed */

    if(shad) {
      m.fx_shadow(shadT, shadC, shadX, shadY);
    }
 
    /* collect menu options */

    O = m.b.getElementsByTagName('a');
     
    /* set up sub menu links */
    
    for(n = 0; n < O.length; n++) {
      o = v(O[n]), c = m.b.className;
      o.b.vskParentMenu = m;
      o.s.cursor = 'pointer';
      o.s.display = 'block';
      o.s.whiteSpace = 'nowrap';
      o.b.className = c+'_item';

      if(o.b.getAttribute('vsk_nested')) {
        o.b.onmouseover = function() {
	  this.className = c+'_item_hover';
	  var M = this.getAttribute('vsk_nested');
	  var y = v(this).y();
	  var a = this.getAttribute('vsk_align') || 'r';
	  V(M).b.vskParentMenu = this.vskParentMenu;
	  if(this.vskParentMenu.b.vskOpenMenu) {
	    if(this.vskParentMenu.b.vskOpenMenu.b != V(M).b)
	      this.vskParentMenu.b.vskOpenMenu.ddmenu_close();
            else
	      return;
	  }
	  if(a == 'r') 
	    this.vskParentMenu.ddmenu_open(M, 'r', -nMarg, y);
	  else
	    this.vskParentMenu.ddmenu_open(M, 'l', nMarg, y);
	  this.vskParentMenu.b.vskOpenMenu = V(M);
	}
      } else {
        o.b.onmouseover = function() { this.className = c+'_item_hover'; };
      }

      o.b.onmouseout = function() { this.className = c+'_item'; };
    
    }
    
  }
}

/******************************************************************************
 ** E X T E N D  V S K  N O D E ***********************************************
 *****************************************************************************/
 /** Class: VSK_Node */

/*****************************************************************************/
/** Method: ddmenu_open
  * Opens an existing drop down menu and aligns it to the element
  *
  * Parameters:
  *
  *	var id - node id of the drop down menu
  *	string align - defines how the dropdown menu is aligned to the
  *	element
  *	<int x> - x offset (px)
  *	<int y> - y offset (px)
  *
  * Align Values:
  *
  *	'b' - bottom alignment, menu will be opened below element
  *	't' - top alignment, menu will be opened above element
  *	'l' - left alignment, menu will be openend on the left side of the
  *	element
  *	'r' - right alignment, menu will be openend on the right side of the
  *	element
  *
  * See Also:
  *
  *	<ddmenu_close>
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.ddmenu_open = function(id, align, x, y) {
  var m = V(id);
  if(!m.b)
    return this;

  /* if menu is already opening bail */
  
  if(m.fx_active('morph'))
    return this;

  VSK_MENU_TIMER = clearTimeout(VSK_MENU_TIMER);
  
  /* if menu is a root menu (it has no parent menus) check it's
   * befriended menus and close them
   */

  if(!m.b.vskParentMenu && m.b.vskMenuFriends) {
    var i;
    for(i = 0; i < m.b.vskMenuFriends.length; i++) {
      if(i == id || V(m.b.vskMenuFriends[i]).b.vskParentMenu)
        continue;
      V(m.b.vskMenuFriends[i]).ddmenu_close(1);
    }
  }
  
  var par = m.b.vskParentMenu;
  while( par ) {
    if(!par.v())
      return this;
    par = par.b.vskParentMenu;
  }
  
  if(!x)
    var x =0;
  if(!y)
    var y =0;
  
  switch(align) {
    case 'b': 
      m.move(this.abs_x()+x, this.abs_y()+this.h()+y);
    break;
    case 'r':
      m.move(this.abs_x()+this.w()+x, this.abs_y()+y);
    break;
    case 'l':
      m.move((this.abs_x()-m.w())+x, this.abs_y()+y);
    break;
    case 't':
      m.move(this.abs_x()+x, (this.abs_y()-m.h()) + y);
    break;
  }
  
  /* make menu visible, dont use hide() method to do so because
   * it only deletes the visibility property
   */

  m.s.visibility = 'visible';
  
  if(m.b.vskUseFx) {
    if(m.b.vskUseFx == 'fade') {
      m.fade(1).fx_fade_in(m.b.vskFxTime);
    } else if(m.b.vskUseFx == 'morph') {
      m.s.overflow = 'hidden';
      m.s.padding = '0px';
      var w = m.w(), h = m.h(), oX = m.x(), oY = m.y();
      m.resize(1,1).fx_morph(w,h,oX,oY,m.b.vskFxTime).onhalt = function() {
        m.s.height = '';
	m.s.padding = '';
      };
    }
  }

  
  return this;
};

/*****************************************************************************/
/** Method: ddmenu_close
  * Close menu and all open nested menus
  *
  * Parameters:
  *
  *	<bool force> - force closing
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.ddmenu_close = function(force) {
  
  VSK_MENU_TIMER = clearTimeout(VSK_MENU_TIMER);
  var m = this;
  
  while( m.b.vskOpenMenu )
    m = m.b.vskOpenMenu;

  if(!m)
    return this;

  while( m ) {
    if(m.b.vskMenuFocus && !force)
      break;
    m.hide(1);
    if( (m = m.b.vskParentMenu) )
      m.b.vskOpenMenu = null;
  }
  
  return this;
};
/******************************************************************************
vegUI Site Kit, Tunnel module

Copyright (c) 2005,2006 Stefan Pratter

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

Contact: vegu@vegui.org
Website: http://www.vegui.org
**/

/******************************************************************************
 * G L O B A L S **************************************************************
 *****************************************************************************/
/** File: vegui.sk.tunnel.js
  *
  * Library for remote scripting without AJAX support by requesting a
  * javascript file via the SCRIPT element or send requests via the
  * IFRAME element
  *
  * Notes: Version
  *
  *	0.1.0 (BETA)
  */

/******************************************************************************
 * V S K  T U N N E L *********************************************************
 *****************************************************************************/
/** Class: VSK_Tunnel
  */

function VSK_Tunnel() {
  this.queue = [];
}

/*****************************************************************************/
/** Function: send
  * sends request to webserver (via IFRAME)
  *
  * Parameters:
  *
  *	string url - url to request
  *	<function ondone> - function to call when the iframe element has
  *	been loaded
  */


VSK_Tunnel.prototype.send = function(url, ondone) {
  if(!document.body)
    return;

  var iframe = document.createElement('iframe');
  iframe.style.position = 'absolute';
  iframe.style.left = '-1000px';
  iframe.style.top = '-1000px';
  iframe.frameName = 'vskt_'+(Math.round(Math.random()*99999)+1);
  iframe.setAttribute('name', iframe.frameName);

  iframe[(typeof iframe.readyState == 'undefined' ? 'onload' : 'onreadystatechange')] = function() {
    if(typeof this.readyState != 'undefined' && this.readyState != 'complete')
      return;
    if(ondone)
      ondone(this);
    var iframe = this;
    setTimeout(function() {document.body.removeChild(iframe); }, 100);
  };
  document.body.appendChild(iframe);
  iframe.src = url;
};


/*****************************************************************************/
/** Function: request
  * Includes javascript (script) from webserver
  *
  * Parameters:
  *
  *	string url - script url
  *	<function ondone> - function to be called when script has been
  *	successfully includes
  *	<bool sync> - include script synchronous to script execution
  */

VSK_Tunnel.prototype.request = function(url, ondone, sync) {

  var script_loaded = function(script) {
    script.parentNode.removeChild(script);
    if(ondone && ondone.exec)
      ondone.exec();
  };

  var head = document.getElementsByTagName('head')[0];
  var script = document.createElement('script');
  script.type = 'text/javascript';

  script.onreadstatechange = function() {
    if(this.readyState == 'complete')
      script_loaded(this);
  };

  script.onload = function() { script_loaded(this);};

  script.src = url;

  if(!sync)
    head.appendChild(script);
  else {
    if(/Apple/.test(navigator.vendor))
      script.appendChild(document.createTextNode(' '));
    else
      script.text = ' ';
    head.appendChild(script);
  }
};
/*
Copyright (c) 2008 Stefan Pratter

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

/******************************************************************************
 * G L O B A L S **************************************************************
 *****************************************************************************/
/** File: vegui.sk.event.js
  *
  * Description:
  *
  * The VegUISiteKit Event Object, allows you to retrieve mouse or keyboard
  * event related data in a cross browser supported fashion
  *
  */

/** Function: ve
  * Wrapper function to return VSK_Event object
  *
  * Parameters:
  *
  *	Event event - javascript event object
  *
  * Returns:
  *
  *	VSK_Event - VSK_Event Object
  */

function ve(event) {
  return new VSK_Event(event);
}

/******************************************************************************
 * V S K  E V E N T ***********************************************************
 *****************************************************************************/
/** Class: VSK_Event
  * VegUISiteKit Event Object
  */
  
/*****************************************************************************/
/** Constructor: VSK_Event
  *
  * Parameters:
  *
  *	<event e> - javascript event object
  *
  */
  
function VSK_Event(e) {
  this.event = e;
};

/*****************************************************************************/
/** Function: rt
  * Retrieve related target from mouseover our mouseout events
  *
  * Returns:
  *
  *	Node - related target
  */

VSK_Event.prototype.rt = function() {
  return vsk_rel_target(this.event);
};

/*****************************************************************************/
/** Function: rt_valid
  * Checks if the related target of a mouseover or mouseout event is a node
  * that is not a child of the specified node. Also checks that the related
  * target is not the specified node itself.
  *
  * Parameters:
  *
  *	Node Node - specified node
  *
  * Returns:
  *
  *	bool - true, related target is not a child of specified node, or the
  *	specified node itself
  *	bool - false, related target is a child of specified node, or the 
  *	specified node itself
  *
  */

VSK_Event.prototype.rt_valid = function(Node) {
  var rt = this.rt();
  return (!v(rt).has_parent(Node) && rt != Node);
    
};

/*****************************************************************************/
/** Function: delta
  * Retrieve mouse delta from mousewheel event
  *
  * Returns:
  *
  *	int delta - mousewheel delta
  */

VSK_Event.prototype.delta = function() {
  if(this.event.wheelDelta)
    if(VSK_I.name == 'Opera' && VSK_I.version <= 9)
      return -(this.event.wheelDetla / 120);
    else
      return this.event.wheelDelta / 120;
  else if(this.event.detail)
    return -this.event.detail / 3;
};

/*****************************************************************************/
/** Function: key_mod
  * Returns weither the shift/alt/ctrl key modifier has been applied to 
  * the event or not
  *
  * Parameters:
  *
  *	string modifier - "ctrl", "alt" or "shift"
  *
  * Returns:
  *
  *	bool - *true* if shift-key was pressed during the event, *false* if not
  */

VSK_Event.prototype.key_mod = function(modifier) {
  return this.event[modifier+'Key'] ? true : false;
};

/*****************************************************************************/
/** Function: key_code
  * Return the key code of a keyboard event (which key was pressed)
  *
  * Returns:
  *
  *	int - key code
  */

VSK_Event.prototype.key_code = function() {
  return (this.event.which ? this.event.which : this.event.keyCode);
};

/*****************************************************************************/
/** Function: key_char
  * Return the character for the key that was pressed 
  *
  * Returns:
  *
  *	string - character for the key that was pressed, if possible
  */

VSK_Event.prototype.key_char = function() {
  return String.fromCharCode(this.key_code());
};

/*****************************************************************************/
/** Function: button
  * Return which mouse button was clicked
  *
  * Returns:
  *
  *	int - mouse button identifier (1 = left, 2 = right, 3 = middle)
  */

VSK_Event.prototype.button = function() {
  return (this.event.which ? this.event.which : this.event.button);
};

/*****************************************************************************/
/** Function: coords
  * Returns current mouse coordinates
  *
  * Returns:
  *
  *	object - .x (x coords), .y (y coords)
  */

VSK_Event.prototype.coords = function() {
  vsk_get_mouse(this.event);
  return {
    x : vskX, y: vskY
  }
};

/*****************************************************************************/
/** Function: coords_node
  * Returns current mouse coordinates inside element that triggered
  * event
  *
  * Returns:
  *
  *	Object - .x (x coords), .y (y coords)
  */

VSK_Event.prototype.coords_node = function() {
  return {
    x : (isNaN(this.event.offsetX) ? this.event.layerX : this.event.offsetX),
    y : (isNaN(this.event.offsetY) ? this.event.layerY : this.event.offsetY)
  };
};

/*****************************************************************************/
/** Function: stop
  * Prevent the default browser response to the event if at all possible
  *
  * Returns:
  *
  *	VSK_Event - self
  */

VSK_Event.prototype.stop = function() {
  if(this.event.preventDefault)
    this.event.preventDefault();
  this.event.returnValue = false;
  return this;
};

/*****************************************************************************/
/** Function: t
  * Returns the source target node of the event
  *
  * Returns:
  *
  *	Node - the source target node of the event
  */

VSK_Event.prototype.t = function() {
  if(this.event.target)
    return this.event.target;
  else if(this.event.srcElement)
    return this.event.srcElement;
  else
    return null;
};
/*
Copyright (c) 2008 Stefan Pratter

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

/******************************************************************************
 * G L O B A L S **************************************************************
 *****************************************************************************/
/** File: vegui.sk.drag.js
  *
  * Description:
  *
  * The VegUISiteKit Drag Library. Introduces drag and drop functionality
  * to the vsk
  *
  * Notes: Version
  *
  *	0.1.0
  *
  * Notes: Dependencies
  *
  *	vegui.sk.std.js
  *	vegui.sk.event.js
  *	vegui.sk.collision.js
  *
  * Notes: Drag Types
  *
  *	0 - self, the node itself is moved
  *	1 - shadow, shadow of the node is moved
  *	2 - frame, wireframe of the node is moved
  *
  * Notes: Drag Modes
  *
  *	0 - Move and place, simply allows  the user to move the node to
  *	a new spot inside it's current parent node
  *	1 - Drag and Drop, allows the user to drag and drop the node,
  *	requiring at least one node to be setup as a drop target via
  *	<VSK_Node::dropinit>
  *
  */

v(window).event_add("load", function() {
  v(document.body).event_add("mouseup", function(e) {
    var E = ve(e || event), t;
    if(window.VSK_DRAG_NODE) {
      var DN = window.VSK_DRAG_NODE;
      if(!DN.b.vskDragMode)
        DN.dragmode(false);
      else if( DN.b.vskDropNode )
        DN.drop( DN.b.vskDropNode );
      else if( DN.b.vskDragMode == 1)
        DN.dragcancel();
      else if( DN.b.vskDragMode == 2)
        DN.dragmode(false);
    }
  });
});

VSK_DRAG_NODE = null;
VSK_DRAG_CLONE = null;
VSK_DROP_TARGETS = {};

/** Constant: VSK_DRAG_Z
  * Z-level of node being dragged when drag type is drag&drop
  */

var VSK_DRAG_Z = 100000;

/** Constant: VSK_DRAG_SHADOW_TRANSPARENCY
  * transparency of the drag shadow (%)
  */

var VSK_DRAG_SHADOW_TRANSPARENCY = 50;

/** Constant: VSK_DRAG_FRAME_STYLE
  * style object to be copied to the dragable frame
  */

var VSK_DRAG_FRAME_STYLE = {
  border : '1px black solid'
};

/** Constant: VSK_DRAG_FRAME_TRANSPARENCY
  * transparency of the drag frame (%)
  */

var VSK_DRAG_FRAME_TRANSPARENCY = 50;

/** Constant: VSK_DRAG_DROP_SENSITIVITY
  * overlap needed for a drop target to be selected
  */

var VSK_DRAG_DROP_SENSITIVITY = 25;

/******************************************************************************
 * V S K  N O D E *************************************************************
 *****************************************************************************/
/** Class: VSK_Node */

/*****************************************************************************/
/** Function: drag_restore 
  * Restores the static behaviour of the element, destroying it's 
  * drag / drop functionality
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.drag_restore = function() {
  var id,N;
  
  if( (id = this.b.vskDropGroupId) ) {
    delete VSK_DROP_TARGETS[id];
  }

  if( (id = this.b.vskDragGroup) ) {
    this.vsk_event_unset("mousedown", '_priv_draginit');
    this.b.vskDragGroup = null;
    if(VSK_DRAG_NODE && VSK_DRAG_NODE.b == this.b) {
      VSK_DRAG_NODE = null;
      if( (N = this.b.vskDragNode) ) {
        N.undock();
	this.b.vskDragNode = null;
      }
    }
  }

  return this;
};

/*****************************************************************************/
/** Function: dropinit
  * Initializes drop functionality on node
  *
  * Parameters:
  *
  *	mixed groupid - drag&drop group id
  * 
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.dropinit = function(groupId) {
  var Node = this;
  this.b.vskDropGroupId = groupId;
  this.b.vskDropSensitivity = VSK_DRAG_DROP_SENSITIVITY;
  VSK_DROP_TARGETS[groupId] = this;
  return this;
};


/*****************************************************************************/
/** Function: dragprep
  * Prepares node for draginit()
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.dragprep = function() {
  if(!this.b.vskDragGroup)
    this.b.vskDragGroup = {};

  this.b.vskLastDragX = null;
  this.b.vskLastDragY = null;
  this.b.onselectstart = function() { return false; };
  this.b.ondragstart = function() { return false; };
};

/*****************************************************************************/
/** Function: draginit
  * Initializes drag functionality on node
  *
  * Parameters:
  *
  *	mixed groupId - drag&drop group id 
  *	<int mode> - drag & drop mode (default = 0)
  *	<int type> - drag & drop type (default = 0)
  * 	<bool lockX> - if true the node can not be moved on the x-axis
  *	<bool lockY> - if true the node can not be moved on the y-axis
  *	<string keyMod> - allows you to set a key modifier that needs to be
  *	pushed along with klicking on the node in order to put it into
  *	drag-mode (e.g 'shift', 'alt')
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.draginit = function(groupId, mode, type, lockX, lockY, keyMod) {
  
  this.dragprep();
  
  if(groupId) 
    this.b.vskDragGroup[groupId] = true;
  
  this.handle("mousedown").vsk_event_add("mousedown", function(Node, e) {
    if(keyMod && !ve(e || event).key_mod(keyMod))
      return;
    Node.dragmode(true, mode, type, lockX, lockY);
    ve(e || event).stop();
  }, '_priv_draginit');

  return this;
  
};

/*****************************************************************************/
/** Function: drop
  * Drops the node onto the specified node
  *
  * Parameters:
  *
  *	VSK_Node Target - Drop Target Node
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.drop = function(Target) {
  
  /* make sure target has same draggroup as this node */

  if(!this.b.vskDragGroup[Target.b.vskDropGroupId])
    return this.dragcancel();

  this.vsk_event_fire("drop", Target);
  Target.vsk_event_fire("drop", this);
  Target.vsk_event_fire("dropdeselect", this);

  return this.dragmode(false);
};

/*****************************************************************************/
/** Function: dragcancel
  * Cancels the drag mode returning the node to its original position and
  * status
  * 
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.dragcancel = function() {
  
  switch(this.b.vskDragType) {
    case 0:
      var P = this.b.vskDragParent;
      this.set_style_str(this.b.vskDragStyle).dock(P);
    break;
  }
  
  this.dragmode(0);
};

/*****************************************************************************/
/** Function: drag_x
  * Returns the current potential x position (only relevent while dragmode
  * is active)
  *
  * Returns:
  *
  *	int - element's potential position on x axis
  */

VSK_Node.prototype.drag_x = function() {
  var N;
  if((N = this.b.vskDragNode))
    return N.x();
  else
    return this.x();
};

/*****************************************************************************/
/** Function: drag_y
  * Returns the current potential y position (only relevent while dragmode
  * is active)
  *
  * Returns:
  *
  *	int - element's potential position on y axis
  */

VSK_Node.prototype.drag_y = function() {
  var N;
  if((N = this.b.vskDragNode))
    return N.y();
  else
    return this.y();
};


/*****************************************************************************/
/** Function: dragmode
  * Toggles drag mode on or off
  *
  * Parameters:
  *
  *	bool b - *true* = on, *false* = off
  *	<int mode> - drag mode
  *	<int type> - drag type
  *	<bool lockX> - if true the node can not be moved on the x-axis
  *	<bool lockY> - if true the node can not be moved on the y-axis
  *
  * Returns:
  *
  *	VSK_Node - self
  */

VSK_Node.prototype.dragmode = function(b, mode, type, lockX, lockY) {

  var Node = this;
  this.b.vskDrag = b;
  
  if(b) {
    window.VSK_DRAG_NODE = this;
    
    this.b.vskDragType = type;
    this.b.vskDragMode = mode;
    this.b.vskDragParent = this.b.parentNode;
    this.b.vskDragStyle = this.style_str();
    this.vsk_event_fire("dragstart");
    
    if(mode) {
      
      /* mode: drag & drop */
      
      switch(type) {
        case 0:
          this.move(
	    this.abs_x(), 
	    this.abs_y()
	  ).level(VSK_DRAG_Z).dock(document.body);
	break;

	case 1:
	  Node = v(this.b.cloneNode(1)).move(
	    this.abs_x(),
	    this.abs_y()
	  ).level(VSK_DRAG_Z).dock(document.body);
	break;
	
	case 2:
	  Node = v(vsk_h('div')).resize(this.w(),this.h()).move(
	    this.abs_x(),
	    this.abs_y()
	  ).level(VSK_DRAG_Z).dock(document.body);
	break;
      }
      
    } else {

      /* mode: move & place */

      switch(type) {
        
	case 1:
	  Node = v(this.b.cloneNode(1)).move(
	    this.x(),
	    this.y()
	  ).level(VSK_DRAG_Z).dock(this.b.parentNode);
	break;

	case 2:
 	  Node = v(vsk_h('div')).resize(this.w(),this.h()).move(
	    this.x(),
	    this.y()
	  ).level(VSK_DRAG_Z).dock(this.b.parentNode);
	break;
      }
     
    }

    if(type) {
      Node.b.vskDrag = true;
      Node.b.vskLastDragX = null;
      Node.b.vskDragMode = mode;
      Node.b.vskDragSource = this;
      Node.b.vskDragGroup = this.b.vskDragGroup;
      this.b.vskDragNode = Node;
      Node.s.cursor = this.s.cursor;
      if(this.b.vskBBox) {
        Node.b.vskBBox = this.b.vskBBox;
      }
    }

    if(type == 1) {
      Node.fade(VSK_DRAG_SHADOW_TRANSPARENCY);
    } else if(type == 2) {
      Node.set_style(VSK_DRAG_FRAME_STYLE).fade(VSK_DRAG_FRAME_TRANSPARENCY);
    }
   
    /* set up the mouse move event */
   
    v(document.body).event_add("mousemove", function(e) {
      
      if(!Node.b.vskDrag)
        return;

      vsk_get_mouse(e || event);
      
      if(Node.b.vskLastDragY === null)
        Node.b.vskLastDragY = vskY;
      if(Node.b.vskLastDragX === null)
        Node.b.vskLastDragX = vskX;
      
      /* if mode is drag & drop, scan for possible targets that
       * could be currently under the node 
       */
      
      if(Node.b.vskDragMode) {
        var i,Targets = VSK_DROP_TARGETS,T,o2,O=0,D;
	
	if(Node.b.vskDragSource)
  	  var S = Node.b.vskDragSource;
        else
	  var S = Node;

	var OD = S.b.vskDropNode;
      
        if(OD)
          O = Math.max(Node.touching(OD.b), OD.touching(Node.b));

        for(i in Node.b.vskDragGroup) {
          if(Targets[i]) {
            T = Targets[i];

            o = Math.max(Node.touching(T.b),T.touching(Node.b));
            if(o && o > T.b.vskDropSensitivity && (o >= O || (D && T.has_parent(D.b)) || (OD && T.has_parent(OD.b)) || (OD && OD == T) ) ) {
	      
              if(D && D.has_parent(T.b))
                continue;

              D = T;

              if(OD && D != OD) {
                OD.vsk_event_fire("dropdeselect", S);
                D.vsk_event_fire("dropselect", S);
              } else if(!OD)
                D.vsk_event_fire("dropselect", S);

              O = o;
            }
          }
        }

 
        if(OD && !D)
          OD.vsk_event_fire("dropdeselect", S);

        S.b.vskDropNode = D;
      }

      /* drop node has been found, fire "dropselect" */


      /* move the node relative to the difference of the
       * current mouse coordinates and the previous mouse
       * coordinates
       */

      Node.move(
        lockX ? null : (Node.x() - (Node.b.vskLastDragX - vskX)),
	lockY ? null : (Node.y() - (Node.b.vskLastDragY - vskY))
      );

      Node.b.vskLastDragX = vskX;
      Node.b.vskLastDragY = vskY;
      
      if(!Node.b.vskDragSource)
        Node.vsk_event_fire("drag");
      else
        Node.b.vskDragSource.vsk_event_fire("drag");
	
    }, 'drag');


  } else {
    
    /* stop drag mode */
     
    window.VSK_DRAG_NODE = null;

    this.b.vskLastDragY = null;
    this.b.vskLastDragX = null;
    
    var DN;

    /* if a drag node was created make sure to remove
     * it from the document
     */
    
    if((DN = this.b.vskDragNode)) {
      
      if(this.b.vskDragMode != 1 && !this.b.vskDropNode) {
        this.move(DN.x(), DN.y());
      }

      DN.undock();
      
      this.b.vskDragNode = null;
    }

    this.vsk_event_fire("dragstop");

    v(document.body).event_unset("mousemove", 'drag');

  }

  return this;
 
  
};
/*
Copyright (c) 2008 Stefan Pratter

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

/******************************************************************************
 * G L O B A L S **************************************************************
 *****************************************************************************/
/** File: vegui.sk.collision.js
  *
  * Description:
  *
  * The VegUISiteKit Collision Library. Introduces functions to check
  * node collisions to the VSK_Node object.
  *
  * Notes: Version
  *
  *	0.1.0
  *
  * Notes: Dependencies
  *
  *	vegui.sk.std.js
  *
  */

/******************************************************************************
 * V S K  N O D E *************************************************************
 *****************************************************************************/
/** Class: VSK_Node */

/*****************************************************************************/
/** Function: touching
  * Checks if this node is colliding with another node on an absolute scale,
  * meaning the nodes can have different parentNodes.
  *
  * Parameters:
  *
  *	Node Node - The node to check for collision
  *
  * Returns:
  *
  *	int - *>0*, collision amount in percent. The amount the node's overlap
  *	eachother
  *	int - *0*, no collision
  */

VSK_Node.prototype.touching = function(Node) {
  
  var T = v(Node);
  
  /* calculate absolute positions of both nodes */

  var mX = this.abs_x(),
      mY = this.abs_y(),
      mW = this.w(),
      mH = this.h(),
      mR = mX+mW,
      mB = mY+mH,
      tX = T.abs_x(),
      tY = T.abs_y(),
      tW = T.w(),
      tH = T.h(),
      tR = tW+tX,
      tB = tH+tY;
 
  var touchesH, touchesV;
  
  /* calculate if the node is colliding horizontally */

  
  if(mX <= tX && mR >= tR)
    touchesH = tW;
  else if(mX <= tX && mR <= tR && mR >= tX)
    touchesH = mR - tX;
  else if(mX >= tX && mR >= tR && mX <= tR)
    touchesH = tR - mX;
  else if(mX >= tX && mR <= tR)
    touchesH = mW;
    
  if(!touchesH)
    return 0;

   /* calculate if the node is colliding vertically */

   if(mY <= tY && mB >= tB)
     touchesV = tH;
   else if(mY <= tY && mB <= tB && mB >= tY)
     touchesV = mB - tY;
   else if(mY >= tY && mB >= tB && mY <= tB)
     touchesV = tB - mY;
   else if(mY >= tY && mB <= tB)
     touchesV = mH;

   if(!touchesV)
     return 0;
  
   return (touchesV * touchesH) / ((tH * tW) / 100);
};
/******************************************************************************
 * G L O B A L S **************************************************************
 *****************************************************************************/
/** File: vegui.sk.slidingmenu.js
  *
  * Dependencies:
  *
  *	<vegui.sk.std.js>
  *	<vegui.sk.ani.js>
  *	<vegui.sk.ani.morph.js>
  */

/** Constant: VSK_SMNU_FX_TIME
  * The time it takes for a menu section to expand or collapse (ms)
  */

var VSK_SMNU_FX_TIME = 200;

/*****************************************************************************/
/** Function: vsk_smnu_init
  * Initializes one ore more menus to support the vegui sitekit slidingmenu
  *
  * Parameters:
  *
  *	<...> - menu header ids
  *
  * Example:
  *
  * (start code)
  * vsk_smnu_init('menu_news')
  * (end)
  */

function vsk_smnu_init() {
  var i,a;
  for(i = 0; i < arguments.length; i++) {
    a = arguments[i];
    if(V(a))
      V(a).s.cursor = 'pointer';
    else
      continue;
    
    if(vsk_cookie_get('smnu_'+a))
      V(a).vsk_smnu_collapse(true);
    
    V(a).b.onmousedown = function() {
      if(this.vskSmnuStatus)
        v(this).vsk_smnu_expand();
      else
        v(this).vsk_smnu_collapse();
    };
  }
}

var VSK_SMNU_FX_TIME = 200;

/******************************************************************************
 * E X T E N D  V S K  N O D E ************************************************
 *****************************************************************************/
/** Class: VSK_Node */

/*****************************************************************************/
/** Method: vsk_smnu_collapse */

VSK_Node.prototype.vsk_smnu_collapse = function(noFX) {
  
  /* attempt to find content node */

  var n = V(this.b.id+'_c');
  if(!n)
    return;

  n.s.overflow = 'hidden';
  n.b.vskSmnuSize = n.h();

  if(!noFX) {
    n.fx_morph(n.w(), 1, null, null, VSK_SMNU_FX_TIME).onhalt = function() {
      n.hide(1);
    };
  } else {
    n.hide(1).fx_morph(n.w(), 1, null, null, 1).onhalt = function() {
      n.hide(1);
    };
  }
  
  this.b.vskSmnuStatus = 1;
  vsk_cookie_set('smnu_'+this.b.id, '1', 1000*60*60*24*356);

};

/*****************************************************************************/
/** Method: vsk_smnu_expand */

VSK_Node.prototype.vsk_smnu_expand = function() {

  /* attempt to find content node */

  var n = V(this.b.id+'_c');
  if(!n || !n.b.vskSmnuSize)
    return;
  
  n.hide(0).fx_morph(
    n.w(),n.b.vskSmnuSize,null,null, VSK_SMNU_FX_TIME
  ).onhalt = function() { n.s.height = '' };

  this.b.vskSmnuStatus = null;

  vsk_cookie_set('smnu_'+this.b.id, '', -1000);
};

