/***********************************************************************
mover.js -- a javascript class supporting draggable HTML content-elements.

Author: James Gourgoutis
Date: 12/11/2007
Version: 1.1

Copyright 2005 James Gourgoutis. All rights reserved. FOR PRIVATE DEMO/RESEARCH
PURPOSES ONLY.  No part of this software may be used, copied, or distributed in
any form without the author's permission.

Usage:

1) Include the mover.js file in your HTML file:

		<SCRIPT SRC="mover.js"></SCRIPT>
		
2) Add the ID of each draggable element into the global "gMovers" list:

		<script language="Javascript">
		<!-- 
			gMovers = ['element1', 'element2', 'element3'];
		// -->
		</script>
		
3) The "grabbable" tab within each element is defined by the first
H1 tag found in that element:

	<DIV id="element1">
		<h1>my title</h1>
		...content...
	</DIV>
	

For further information, refer to http://yojimg.net/work/projects/mover/	
***********************************************************************/

// ensure that cookie library is included
if (typeof(setMetaCookie) != "function") {
	//document.write('<SCR'+'IPT SRC="/scripts/yojimg.js"></SCRIPT>');
  var n = document.createElement("script");
  n.src = "/scripts/yojimg.js";
  document.body.appendChild(n);
}

//constructor
function Mover(element_id, bRememberPosition) {		
  if (element_id) {
    // attributes
    this.divId = element_id;
    this.rememberPos = (arguments.length > 1) ? bRememberPosition : true;
    this.docObjectRef = document.getElementById(this.divId);
    this.header = Mover.getHeaderElement(this.docObjectRef);
                
    // attach some event handlers
    this.header.onmouseover = Mover.handleOnMouseOver;
    this.header.onmousedown = Mover.handleOnMouseDown;
    this.x;
    this.y;
    this.dx;
    this.dy;
    this.clicked = false;
    // store a list of Mover object references for later retrieval
    Mover.list[Mover.list.length] = this;
    
    // reposition the content element to any stored position
    Mover.relocate(this);
  }
};

// class properties & methods
Mover.author = 'Jim Gourgoutis';
Mover.version = '1.0';
Mover.current = null;
Mover.list = [];
Mover.gCookieName = 'moverCoords';

// returns a reference to the "grabbable" H1 tab in the content element
Mover.getHeaderElement = function(anEle) {
   // first enclosed H1 tag should be the box's header
  var header = anEle.getElementsByTagName('h1')[0]; 
  return(header);
};

// mouseDown event handler
Mover.handleOnMouseDown = function (anEvent) {	
	if (!anEvent) {
		anEvent = window.event; //IE compatibility
  }

	var m = Mover.getMoverById(this.parentNode.id);
	Mover.current = m;
	m.clicked = true;
	m.readPosition();
	Mover.adjustZIndex(m);
			
	var coords = Mover.getPointerCoords(anEvent);
	m.dx = coords[0] - m.x;
	m.dy = coords[1] - m.y;
	
	//attach the other event handlers				
	if (document.addEventListener) { // DOM-2 Event Model
		document.addEventListener("mousemove", Mover.handleOnMouseMove, true);
		document.addEventListener("mouseup", Mover.handleOnMouseUp, true);
	}
	else if (document.attachEvent) { // IE 5+ Event Model
		document.attachEvent("onmousemove", Mover.handleOnMouseMove);
		document.attachEvent("onmouseup", Mover.handleOnMouseUp);				
	}
	else { // IE 4 Event Model
		document.onmousemove = Mover.handleOnMouseMove;
		document.onmouseup = Mover.handleOnMouseUp;
	}
	
	if (anEvent.stopPropagation) anEvent.stopPropagation(); // DOM-2
	else anEvent.cancelBubble = true; // IE
	
	if (anEvent.preventDefault) anEvent.preventDefault(); // DOM-2
	else anEvent.returnValue = false; // IE
};

// bring the clicked element into pointer-focus
Mover.adjustZIndex = function(aMoverObj) {
	for (f in Mover.list) {
		if (Mover.list[f] == aMoverObj)
			aMoverObj.docObjectRef.style.zIndex = 1;
		else
			//Mover.list[f].docObjectRef.style.zIndex = 'auto';
			Mover.list[f].docObjectRef.style.zIndex = 0;
	}
};


// calculate the current coordinates of the mouse pointer
Mover.getPointerCoords = function(anEvent) {							
	var coords;
	coords = [anEvent.clientX, anEvent.clientY];
	return(coords);
};

// mouseOver event handler
Mover.handleOnMouseOver = function() {
	this.style.cursor = 'move';
};

// mouseMove event handler
Mover.handleOnMouseMove = function(anEvent) {
	if (!anEvent)
		anEvent = window.event; //IE compatibility
					
	var m = Mover.current;

	if (m.clicked){
	
		// move to Mover_getPointerCoords()
		var coords = Mover.getPointerCoords(anEvent);
		m.docObjectRef.style.left = (coords[0] - m.dx) + 'px';
		m.docObjectRef.style.top = (coords[1] - m.dy) + 'px';
		m.docObjectRef.style.opacity = 0.7;
		m.docObjectRef.style.filter  = "progid:DXImageTransform.Microsoft.Alpha(opacity = 50)";
	}
	
	if  (anEvent.stopPropagation) anEvent.stopPropagation; // DOM-2
	else anEvent.cancelBubble = true; // IE
};

// mouseUp event handler
Mover.handleOnMouseUp = function(anEvent) {
	if (!anEvent)
		anEvent = window.event; //IE compatibility
		
	var m = Mover.current;
	
	m.docObjectRef.style.opacity = 1;
	m.docObjectRef.style.filter  = "progid:DXImageTransform.Microsoft.Alpha(opacity = 100)";
	
	m.clicked = false;
	m.saveLocation();
	
	// unregister assigned event handlers
	if (document.removeEventListener) { // DOM-2
		document.removeEventListener("mouseup", Mover.handleOnMouseUp, true);
		document.removeEventListener("mousemove", Mover.handleOnMouseMove, true);
	}
	else if (document.detachEvent) { // IE 5+
		document.detachEvent("onmouseup", Mover.handleOnMouseUp);
		document.detachEvent("onmousemove", Mover.handleOnMouseMove);
	}
	else { // IE 4
		// nothing here intentionally
	}
	
	// stop event propagation
	if (anEvent.stopPropagation) anEvent.stopPropagation(); // DOM-2
	else anEvent.cancelBubble = true; // IE
	
};


// translation between an HTML DIV object's ID and a Mover object -- used to
// work around the "this" keyword problem.
Mover.getMoverById = function(eleId) {
	var result;
	for (f in Mover.list) {
		if (Mover.list[f].divId == eleId) result = Mover.list[f];
	}
	return result;
};


// reposition content elements to stored coordinates when the
// page loads.
Mover.relocate = function(aMover) {

	//read stored coords from cookie, 
	//then move content element to new position
	var coords = getMetaCookie(aMover.divId, Mover.gCookieName);
	if (coords) {
		aMover.docObjectRef.style.left = coords.split(',')[0];
		aMover.docObjectRef.style.top = coords.split(',')[1];
	}
};

// instantiates new Mover objects based on IDs in gMover list
Mover.registerElements = function() {
	// disable code if browser is obsolete
	if (Mover.checkBrowserVer()) {
		for (f in gMovers) {
			new Mover(gMovers[f]);
		}
	}
};


// browser sniffer code -- can be extended as necessary
Mover.checkBrowserVer = function() {
	//alert(parseInt(navigator.appVersion));
	
	if ( parseInt(navigator.appVersion) < 5 &&	
		navigator.appName.indexOf("Netscape") != -1 ) {
		var msg = "Your browser is not fully supported, so you may";
		msg += " experience erratic results.  Would you like to upgrade";
		msg += " to a modern browser now?";
		if (confirm(msg))
			window.location = "http://getfirefox.com";
		return(false);
	}
	
	return(true);
};



Mover.prototype = {
  // calculate the upper-left coords of the draggable element
  readPosition: function () {
    this.x = parseInt(this.docObjectRef.style.left);
    this.y = parseInt(this.docObjectRef.style.top);
  },
  // store new location for dragged element
  saveLocation: function() {
  	// save new coordinates in cookie
  	// this could be replaced with an AJAX call to a server-side
  	// script which writes the coords to a DB...when the user logs into his/her
  	// personalized page, the coords for each element could get called into the page
  	// (e.g., via PHP) and plugged into the CSS to directly position the element...
    if(this.rememberPos) {
      setMetaCookie(this.divId, Mover.gCookieName, this.docObjectRef.style.left + ',' + this.docObjectRef.style.top);
    }
  }

};



