
/*------------------------------------------------------------------------*/
/*	Globals for the element                                              */
/*------------------------------------------------------------------------*/


/*------------------------------------------------------------------------*/
/*	Properties                                                                  */
/*------------------------------------------------------------------------*/


/*------------------------------------------------------------------------*/
/*	Initialisation.                                                              */
/*------------------------------------------------------------------------*/


var EDITPANE_BASE= "dhlib/";
var EDITPANE_ID_PREFIX = "EDP_";


/*
	Determine whether an element is part of a "component" 
	(like an image-with-caption assembly) inserted by the 
	edit pane animator code.
	
  Parameters:
  	e 		The element to be examined
 
  Returns:
  	True or false. 
*/
function editpaneIsComponentElement(e) 
{
	/*
		Examine the id to see if it is of the component form.
	*/
	if (e.id==null) return false;
	if (e.id.length<EDITPANE_ID_PREFIX.length) return false;
	return (e.id.substr(0, EDITPANE_ID_PREFIX.length) == EDITPANE_ID_PREFIX)
}


/**
	Find an ancestor of a given element with a given tag type.
	If the element is itself of the specified type it is returned.
	The search does not continue outside the edit pane container.
	
  Parameters:
  	sTag	The tag name to find or a semi-colon delimited list of names
  	e			The element in the edit pane
 
  Returns:
  	An element of the specified type or null if none found. 
*/
function editpaneFindAncestorElement(sTag, e) 
{
  while ((e!=null) && sTag!=e.tagName && sTag.indexOf(e.tagName+";")==-1) {
	if (e==window._editpane.element) return null;
  	e = e.parentElement;
  }
  return editpaneIsChildOf(e, window._editpane.element) ? e : null;
}

/**
	Determine whether one element is (strictly) conatained in
	another element.
	
  Parameters:
  	child			The putative descendent element
  	container	The putative container element
 
  Returns:
  	True or false 
*/
function editpaneIsChildOf(child, container)
{
	if (child==container) return false;
	for (var e=child; e!=null; e=e.parentElement) {
		if (e==container) return true;
	}
	return false;
}


/**
	Return a range corresponding to the current document 
	selection (which may or may not be inside the edit pane).
	
  Parameters: 
  	None
 
  Returns:
  	A TextRange or controlRange 
*/
function editpaneGetDocSelectedRange() 
{
	return document.selection.createRange();
}


/**
	Return an element corresponding to the current document 
	selection (which may or may not be inside the edit pane).
	If a control is selected this is the control element, if text is
	selected it is the parent element of the text range.
	
  Parameters: 
  	rg 	Optional. A range representing the current selection.
 
  Returns:
  	An element or null 
*/
function editpaneGetDocSelectedElement(rg) 
{
	switch (document.selection.type) {
	
		case "None": 
		case "Text": 	
			if (rg==null) rg = document.selection.createRange();
			return rg.parentElement();

		case "Control": 	
			if (rg==null) rg = document.selection.createRange();
			return rg.item(0);
	
	}
}

/**
	Find the first text node contained in a given node. If the given
	node is itself a text node it is returned.
	
  Parameters: 
  	e					The node to be searched
  	bNonNull		If true don't return zero-length nodes
  	bNoCaption	If true don't return caption text nodes
 
  Returns:
  	A text node or null 
*/
function editpaneFindTextNode(e, bNonNull, bNoCaption)
{ 
	if ((e.nodeType==3) && (!bNonNull || e.length>0) && (!bNoCaption || e.parentNode.tagName!="CAPTION")) {
		return e;
	}
	for (var n=0; n<e.childNodes.length; n++) {
		var t = editpaneFindTextNode(e.childNodes(n), bNonNull, bNoCaption);
		if (t != null) return t;
	}
	return null;
}

/**
	Handle oncontextmenu.
	Create a CEditpaneComponent object from the selection
	and invoke its showContextMenu() method. The return from
	this method call becomes the return from this handler and so
	determines whether the default context menu is shown.
*/
function e_editpaneContextmenu()
{
	var cmp = new CEditpaneComponent(event.srcElement);
	return cmp.showContextMenu(event.clientX, event.clientY)
}


/**
	Handle onbeforecut.
	If an element of a component assemby is being cut then
	expand the selection to encompass the entire assembly
	before the operation takes place.
*/
function e_editpaneBeforecut()
{
	var cmp = new CEditpaneComponent(event.srcElement);
	cmp.beforeDelete();
	return true;
}

/**
	Handle onkeydown.
	If an element of a component assemby is being deleted 
	then	expand the selection to encompass the entire assembly
	before the operation takes place.
*/
function e_editpaneKeydown()
{
	switch (event.keyCode) {
		
		case 46: //Del
			var cmp = window._editpane.getSelectedComponent();
			cmp.beforeDelete();
			return true;
	
		case 33: //PgUp
			window._editpane.element.doScroll("Up");
			event.cancelBubble=true;
			return false;
	
		case 34: //PgDn
			window._editpane.element.doScroll("Down");
			event.cancelBubble=true;
			return false;
	
		default:
			return true;
	
	}
}


/**
	Handle onreadystatechange
	When the document is interactive home the cursor.
*/
function e_editpaneReadystatechange()
{
	/*
		We need to look for both interactive and 
		complete because if all images in the document
		are taken from cache then there is no interactive
		state, the document goes straight to complete and
		we never see interactive.
	*/
	if (document.readyState=="interactive") { 
		window._editpane.cursorHome(); 
	}
	if (document.readyState=="complete") { 
		window._editpane.cursorHome(); 
	}
}



/**
	Handle onselectionchange.
	EXPERIMENTAL. 

*/
function e_editpaneSelectionchange()
{ 
	if (document.selection.type=="Control") return;

	var rg = document.selection.createRange();
	var p = rg.parentElement();
	if (p != window._editpane.element) return;

	var t = editpaneFindTextNode(window._editpane.element);
	if (t==null) return;

	rg = document.selection.createRange();
	rg.moveToElementText(t.parentNode);
    rg.collapse();
    rg.select();   
}


/**
	Handle onmousewheel.
	IE6 ONLY. 

*/
function e_editpaneMousewheel()
{ 
	var wd = event.wheelData;
}

/**
	Handler that just cancels an event.
*/
function e_editpaneCancelEvent()
{
	event.cancelBubble = true;
	event.returnValue = false;
	return false;
}

/**
	Determine whether an element is selected in the edit pane.
	
  Parameters: 
  	None
 
  Returns:
  	True or false 
*/
function m_editpaneIsElementSelected() 
{
	return document.selection.type=="Control" && this.getSelectedElement()!=null;
}

/**
	Determine whether anything is selected in the edit pane.
	
  Parameters: 
  	None
 
  Returns:
  	True or false 
*/
function m_editpaneHasSelection() 
{
	return this.getSelectedElement()!=null;
}

/**
	Determine whether blocked text is selected in the edit pane.
	
  Parameters: 
  	None
 
  Returns:
  	True or false 
*/
function m_editpaneIsTextSelected() 
{/////////////////////////////////////////////////////////////////////////
	return document.selection.type=="Text" && this.getSelectedElement()!=null;
}


/**
	Return a range corresponding to the current document 
	selection or null if the selection is not contained within
	the edit pane.
	
  Parameters: 
  	None
 
  Returns:
  	A TextRange or controlRange or null
*/
function m_editpaneGetSelectedRange() 
{
	var rg = editpaneGetDocSelectedRange();
	var e = editpaneGetDocSelectedElement(rg);
	return e == this.element || editpaneIsChildOf(e, this.element) ? rg : null;
}

/**
	Return the element selected in the edit pane if any. If text is
	selected then the parent element of the selection is returned
	unless it is not contained within the edit pane, in which case
	null is returned.
	
  Parameters: 
  	rg 	Optional. A range representing the current selection.
 
  Returns:
  	An element or null 
*/
function m_editpaneGetSelectedElement(rg) 
{
	var e = editpaneGetDocSelectedElement(rg);
	return editpaneIsChildOf(e, this.element) ? e : null;
}

/**
	Return a CEditpaneComponent object corresponding to 
	the element selected in the edit pane if any.
	
  Parameters: 
  	rg 	Optional. A range representing the current selection.
 
  Returns:
  	A CEditpaneComponent object
*/
function m_editpaneGetSelectedComponent(rg) 
{
	if (document.selection.type == "Control") 
		return this.getCursorComponent();
	
	//IF ramge length >0 the return
	
	var eSel = editpaneGetDocSelectedElement(rg);
	var e = editpaneFindAncestorElement(";TABLE;IMG;", eSel);
	return new CEditpaneComponent(e); 
}

/**
	Return a CEditpaneComponent object corresponding to 
	the element that contains the cursor.
	
  Parameters: 
  	rg 	Optional. A range representing the current selection.
 
  Returns:
  	A CEditpaneComponent object
*/
function m_editpaneGetCursorComponent(rg) 
{
	var eSel = editpaneGetDocSelectedElement(rg);
	if (eSel==null) return null;
	return new CEditpaneComponent(eSel);	
}

/**
	Set focus on the edit pane and set a suitable selection.
	
  Parameters: 
	 None
	 
  Returns:
  	 Nothing
*/
function m_editpaneCursorHome() 
{

	var obj = this.element
  var position = {x:0,y:0};

  do{
   position.x += obj.offsetLeft;
   position.y += obj.offsetTop;
   obj = obj.offsetParent;
  } while(obj)

	this.element.style.height = document.body.clientHeight - position.y - 16

	var t = editpaneFindTextNode(this.element, true, true);
	if (t==null) t = editpaneFindTextNode(this.element, true, false);
	if (t==null) return;

	rg = document.selection.createRange();
	rg.moveToElementText(t.parentNode);
    rg.collapse();
    rg.select();   
}


/**
	Set focus on the edit pane and set a suitable selection.
	
  Parameters: 
	 None
	 
  Returns:
  	 Nothing
*/
function m_editpaneFocus() 
{
	this.element.focus();

	if (document.selection.type!="None") return;

	var rg = document.selection.createRange();
	var p = rg.parentElement();
	if (editpaneIsChildOf(p, this.element)) return;

	this.cursorHome();
}


/**
	Execute a formatting command on the edit pane.
	
  Parameters: 
	cmd 	The command to be executed.
	opt		The command options.
	 
  Returns:
  	A CEditpaneComponent object
*/
function m_editpaneExecCommand(cmd, opt) 
{
  if  (opt=="removeFormat") {
    cmd=opt;
    opt=null;
  }

  if (opt==null) 
  	document.execCommand(cmd);
  else {
  	document.execCommand(cmd, false, opt);
  	}
  
  this.focus();
}


/**
	Insert an image into the edit pane at the cursor. The image is inserted
	as a component assembly including a table and caption.
	
  Parameters: 
  	img	An img element representing the img to be inserted.
 
  Returns:
  	Nothing
*/
function m_editpaneInsertImage(img) 
{
	if (document.selection.type=="Control") return;
	
	var eSel = document.selection.createRange().parentElement();
	var p = editpaneFindAncestorElement("P;TD;DIV;", eSel);
	if (p==null) {
		alert("Put the cursor in the paragraph or table in which the image is to be inserted");
		return;
	}

	var table = document.createElement("<table>");
	table.id = EDITPANE_ID_PREFIX+"AREF_"+document.uniqueID
	
	if (p.tagName!="TD") {
		table.style.marginRight="10px";
		table.style.marginBottom="10px";
		table.align="left";
	}

	var tr = table.insertRow();
	tr.id = EDITPANE_ID_PREFIX+"AREF_"+document.uniqueID;
	
	var td = tr.insertCell();
	td.id = EDITPANE_ID_PREFIX+"AREF_"+document.uniqueID;
	td.align="center";

    var cp = table.createCaption()
	cp.id = EDITPANE_ID_PREFIX+"AREF_"+document.uniqueID;
    cp.align = "bottom"
    cp.innerText = "Click here to edit caption"

    var i = document.createElement("<img border=0>");
	i.id = EDITPANE_ID_PREFIX+"AREF_"+document.uniqueID
   i.src=img.src;
   
	td.appendChild(i)
	
	if (p.childNodes.length==0)
	    p.insertBefore(table); ///////////// the argument must be a child (!)
	else 
    	p.insertBefore(table, p.childNodes[0]); 

  //  oNode.style.width='100px';
//    oNode.style.length='100px';
//    oNode.align = 'left'
    
    /*  
    	Set the new image selected for resizing.
    */
    var oControlRange = document.body.createControlRange();
    oControlRange.add(i);
    oControlRange.select();	
}


/**
	Insert a file attachment into the edit pane at the cursor. 
	
  Parameters: 
  	img	An img element representing the img to be inserted.
 
  Returns:
  	Nothing
*/
function m_editpaneInsertFile(img) 
{
	if (document.selection.type=="Control") return;
	
	var eSel = document.selection.createRange().parentElement();
	var p = editpaneFindAncestorElement("P;TD;", eSel);
	if (p==null) {
		alert("Put the cursor in the paragraph or table in which the image is to be inserted");
		return;
	}

	var table = document.createElement("<table>");
	table.id = EDITPANE_ID_PREFIX+"AREF_"+document.uniqueID
	
	if (p.tagName=="P") {
		table.style.marginRight="10px";
		table.style.marginBottom="10px";
		table.align="left";
	}

	var tr = table.insertRow();
	tr.id = EDITPANE_ID_PREFIX+"AREF_"+document.uniqueID;
	
	var td = tr.insertCell();
	td.id = EDITPANE_ID_PREFIX+"AREF_"+document.uniqueID;
	td.align="center";

    var cp = table.createCaption()
	cp.id = EDITPANE_ID_PREFIX+"AREF_"+document.uniqueID;
    cp.align = "bottom"
    cp.innerText = img.title

	var a = document.createElement("a");
	tr.id = EDITPANE_ID_PREFIX+"AREF_"+document.uniqueID;

	/*The editor is used by default for content sheets, but may also be used for Catalog items */
	a.href = window._editpane.imgPath+"/"+img.id.substring(3);

    var i = document.createElement("<img border=0>");
	i.id = EDITPANE_ID_PREFIX+"AREF_"+document.uniqueID
   i.src=img.src;
   
	a.appendChild(i);
	td.appendChild(a);
	
	if (p.childNodes.length==0)
	    p.insertBefore(table); ///////////// the argument must be a child (!)
	else 
    	p.insertBefore(table, p.childNodes[0]); 

}


/**
	Insert an image into the edit pane at the cursor. The image is inserted
	as a component assembly including a table and caption.
	
  Parameters: 
  	img	An img element representing the img to be inserted.
 
  Returns:
  	Nothing
*/
function m_editpaneInsertRow() 
{
	if (document.selection.type=="Control") {
		///here check for table sleceted and insert row as the FIRST row (while other code inserts after cursor row)
	
		return;
	}
	
	
	var eSel = document.selection.createRange().parentElement();
	var tdSel = editpaneFindAncestorElement("TD", eSel);
	if (tdSel==null) {
		alert("Put the cursor in the table in which a row is to be inserted");
		return;
	}

	var trSel = editpaneFindAncestorElement("TR", tdSel);
	var tbodySel = editpaneFindAncestorElement("TBODY", tdSel);
	var tableSel = editpaneFindAncestorElement("TABLE", tdSel);

	var nCols = trSel.cells.length
	
	var tr = tbodySel.insertRow(-1);
	tr.id = EDITPANE_ID_PREFIX+"AREF_"+document.uniqueID;
	
		for (var j=0; j<nCols; j++) {
			var td = tr.insertCell();
			td.id = EDITPANE_ID_PREFIX+"TABL_"+document.uniqueID;
			td.align="left";
			td.vAlign="top";
			td.style.border = "1px solid black";
			td.style.padding = "6px";
			td.width=Math.floor(100/nCols)+"%";
		}

	//table.rows.add(tr);
	
}


/**
	Insert an image into the edit pane at the cursor. The image is inserted
	as a component assembly including a table and caption.
	
  Parameters: 
  	img	An img element representing the img to be inserted.
 
  Returns:
  	Nothing
*/
function m_editpaneInsertTable(nRows, nCols) 
{
	if (document.selection.type=="Control") return;
	
	var eSel = document.selection.createRange().parentElement();
	var p = editpaneFindAncestorElement("P", eSel);
	if (p==null) p = editpaneFindAncestorElement("TD", eSel);
	if (p==null) {
		alert("Put the cursor in the paragraph or table in which the new table is to be inserted");
		return;
	}
	
	var table = document.createElement("<table style='border: 1px solid black; border-collapse:collapse;margin-bottom:1em;width:100%'>");
	table.id = EDITPANE_ID_PREFIX+"TABL_"+document.uniqueID

	for (var i=0; i<nRows; i++) {
		var tr = table.insertRow();
		tr.id = EDITPANE_ID_PREFIX+"TABL_"+document.uniqueID;
		for (var j=0; j<nCols; j++) {
			var td = tr.insertCell();
			td.id = EDITPANE_ID_PREFIX+"TABL_"+document.uniqueID;
			td.align="left";
			td.vAlign="top";
			td.style.border = "1px solid black";
			td.style.padding = "6px";
			td.width=Math.floor(100/nCols)+"%";
		}
	}

    var cp = table.createCaption()
	cp.id = EDITPANE_ID_PREFIX+"TABL_"+document.uniqueID;
    cp.align = "bottom"
    cp.innerText = "Click here to edit caption"

	if (p.childNodes.length==0)
	    p.insertBefore(table); ///////////// the argument must be a child (!)
	else 
    	p.insertBefore(table, p.childNodes[0]); 

    /*  
    	Set the new table selected for resizing.
    */
    var oControlRange = document.body.createControlRange();
    oControlRange.add(table);
    oControlRange.select();	
}

/**
	
	
  Parameters: 
	 b     Optional. True to set source mode, false to unset. If omitted toggle mode.
	 
  Returns:
  	 Nothing
*/
function m_editpaneSetSourceMode(b) 
{
	if (b!=null && b==this.sourceMode) return;
	
	if (this.sourceMode) {
		var src = this.element.innerText;
		this.element.innerHTML = src;
		this.element.style.width = this.elementWidth;
		this.element.style.fontSize = this.fontSize;
		this.sourceMode = false;
	}
	else {
		this.element.innerText = this.element.innerHTML;
    	this.elementWidth = this.element.style.width;
		this.fontSize = this.element.style.fontSize;
		this.element.style.width = "100%";
		this.element.style.fontSize = "0.8em";
		this.sourceMode = true;
	}
}

/**
	
  Returns:
  	 True if the pane is currently in source mode.
*/
function m_editpaneIsSourceMode() 
{
	return this.sourceMode;
}

/**
	Get the HTML content of the edit pane.	
	
  	Parameters: 
  		None.
 
  	Returns:
  		The HTML content of the edit pane.
*/
function m_editpaneGetHtml() 
{
	if (this.sourceMode) 
		return this.element.innerText
	else
		return this.element.innerHTML
}

/**
	Get the HTML content of the edit pane with font tags removed.	
	
  	Parameters: 
  		None.
 
  	Returns:
  		The cleaned HTML content of the edit pane.
*/
function m_editpaneGetCleanHtml() 
{
	var fonts = e_editPane.document.body.all.tags("FONT");
	var curr;
	for (var i = fonts.length - 1; i >= 0; i--) {
		curr = fonts[i];
		if (curr.style.backgroundColor=="#ffffff") curr.outerHTML = curr.innerHTML;
	}
	return this.element.innerHTML
}



/**
	A CEditpane object is an animator class used to wrap a content editable
	pane allowing it to be used in conjunction with a toolbar and filebar.

  Parameters: 
	idPane 			The id of the editable element to be wrapped.
	idToolbar		The id of the associated toolbar.
	sImagePath	The path of the image (defaults to cpo)
	 
*/
function CEditpane(idPane, idToolbar, sImgPath)
{

	/*set the path for the image*/
	this.imgPath = sImgPath==null ? "cpo" : sImgPath;

	/*
		Get the element we are wrapping.
	*/
	this.element = document.all[idPane];
	
	
//	this.element = document.getElementById(idPane);
	if (this.element==null) {
		alert("Invalid ID "+idPane+"passed to CEditpaneToolbar constructor");
		return;
	}
	
	/*
		Member variables.
	*/
	this.sourceMode = false;
	
	/*
		Set up the member functions.
	*/
	this.getSelectedElement = m_editpaneGetSelectedElement;
	this.getSelectedRange = m_editpaneGetSelectedRange;
	this.getSelectedComponent = m_editpaneGetSelectedComponent;
	this.getCursorComponent = m_editpaneGetCursorComponent;
	this.isTextSelected = m_editpaneIsTextSelected;
	this.isElementSelected = m_editpaneIsElementSelected;
	this.hasSelection = m_editpaneHasSelection;
	this.execCommand = m_editpaneExecCommand;
	this.focus = m_editpaneFocus;
	this.cursorHome = m_editpaneCursorHome;
	this.insertImage = m_editpaneInsertImage;
	this.insertFile = m_editpaneInsertFile;
	this.getHtml = m_editpaneGetHtml;
	this.getCleanHtml = m_editpaneGetCleanHtml;
	this.setSourceMode = m_editpaneSetSourceMode;
	this.isSourceMode = m_editpaneIsSourceMode;
	
	
	/*
		Instantiate the wrapper object for the toolbar element.
	*/
	this.toolbar = new CEditpaneToolbar(idToolbar, this)

	/*
		Set up the event handlers. Cancel dragenter so as to prevent images 
		being dragged around and becoming separated from their table and
		caption assemblies. (Cancelling dragstart on the images seems to 
		give rise to problems with onmouseout being driven strangely.)
	*/
	with (this.element) {
		onkeydown = e_editpaneKeydown ;
		onbeforecut = e_editpaneBeforecut ;
		oncontextmenu = e_editpaneContextmenu ;
		ondragenter = e_editpaneCancelEvent;
		ondragleave = e_editpaneCancelEvent;
		contentEditable = true;
	}	


///////////Look for situation of blank (white space) inner html and set to <p> </p>
//////////Look for situation of text only with no markup and set <p> tags around the text
//////look for top-level text nodes (child nodes of container div)....
	

	/*
		Set up document level event handlers.
	*/
	if (document.onreadystatechange!=null) alert("Document has a handler set for onreadystatechange which is being replaced");
	document.onreadystatechange = e_editpaneReadystatechange;
	//document.onselectionchange = e_editpaneSelectionchange;
}


/*------------------------------------------------------------------------*/
/*	CEditpaneToolbar class          									 */
/*------------------------------------------------------------------------*/


/**
	Toolbar action handler called when corresponding icon is pressed.

  	Parameters: 
		editPane		The CEditpane object wrapping the editable element.
		rg					A range corresponding to the current selection.
		sType			The type of selection ("None/Text/Control").
	 
*/
function toolbarActionCut(editPane, rg, sType) 
{ 
	var cmp = editPane.getSelectedComponent();
	cmp.beforeDelete();
	editPane.execCommand("cut");
}

/**
	Toolbar action handler called when corresponding icon is pressed.

  	Parameters: 
		editPane		The CEditpane object wrapping the editable element.
		rg					A range corresponding to the current selection.
		sType			The type of selection ("None/Text/Control").
	 
*/
function toolbarActionCopy(editPane, rg, sType) 
{ 
	editPane.execCommand("copy");
}

/**
	Toolbar action handler called when corresponding icon is pressed.

  	Parameters: 
		editPane		The CEditpane object wrapping the editable element.
		rg					A range corresponding to the current selection.
		sType			The type of selection ("None/Text/Control").
	 
*/
function toolbarActionPaste(editPane, rg, sType) 
{ 
	editPane.execCommand("paste");
}

/**
	Toolbar action handler called when corresponding icon is pressed.

  	Parameters: 
		editPane		The CEditpane object wrapping the editable element.
		rg					A range corresponding to the current selection.
		sType			The type of selection ("None/Text/Control").
	 
*/
function toolbarActionBold(editPane, rg, sType) 
{ 
	editPane.execCommand("bold");
}

/**
	Toolbar action handler called when corresponding icon is pressed.

  	Parameters: 
		editPane		The CEditpane object wrapping the editable element.
		rg					A range corresponding to the current selection.
		sType			The type of selection ("None/Text/Control").
	 
*/
function toolbarActionItalic(editPane, rg, sType) 
{ 
	editPane.execCommand("italic");
}

/**
	Toolbar action handler called when corresponding icon is pressed.

  	Parameters: 
		editPane		The CEditpane object wrapping the editable element.
		rg					A range corresponding to the current selection.
		sType			The type of selection ("None/Text/Control").
	 
*/
function toolbarActionUnderline(editPane, rg, sType) 
{ 
	editPane.execCommand("underline");
}

/**
	Toolbar action handler called when corresponding icon is pressed.

  	Parameters: 
		editPane		The CEditpane object wrapping the editable element.
		rg					A range corresponding to the current selection.
		sType			The type of selection ("None/Text/Control").
	 
*/
function toolbarActionLeft(editPane, rg, sType) 
{ 
	editPane.execCommand("justifyleft");
}

/**
	Toolbar action handler called when corresponding icon is pressed.

  	Parameters: 
		editPane		The CEditpane object wrapping the editable element.
		rg					A range corresponding to the current selection.
		sType			The type of selection ("None/Text/Control").
	 
*/
function toolbarActionCenter(editPane, rg, sType) 
{ 
	editPane.execCommand("justifycenter");
}

/**
	Toolbar action handler called when corresponding icon is pressed.

  	Parameters: 
		editPane		The CEditpane object wrapping the editable element.
		rg					A range corresponding to the current selection.
		sType			The type of selection ("None/Text/Control").
	 
*/
function toolbarActionRight(editPane, rg, sType) 
{ 
	editPane.execCommand("justifyright");
}

/**
	Toolbar action handler called when corresponding icon is pressed.

  	Parameters: 
		editPane		The CEditpane object wrapping the editable element.
		rg					A range corresponding to the current selection.
		sType			The type of selection ("None/Text/Control").
	 
*/
function toolbarActionOList(editPane, rg, sType) 
{ 
	editPane.execCommand("insertorderedlist");
}

/**
	Toolbar action handler called when corresponding icon is pressed.

  	Parameters: 
		editPane		The CEditpane object wrapping the editable element.
		rg					A range corresponding to the current selection.
		sType			The type of selection ("None/Text/Control").
	 
*/
function toolbarActionUList(editPane, rg, sType) 
{ 
	editPane.execCommand("insertunorderedlist");
}
 

/**
	Toolbar action handler called when corresponding icon is pressed.

  	Parameters: 
		editPane		The CEditpane object wrapping the editable element.
		rg					A range corresponding to the current selection.
		sType			The type of selection ("None/Text/Control").
	 
*/
function toolbarActionCreateLink(editPane, rg, sType) 
{ 
	var eSel = editPane.getSelectedElement(rg);

	var a = editpaneFindAncestorElement("A", eSel);
	  
	var dlgdata = new Array();
	dlgdata["url"] = a ? a.href : "http:\/\/";

	dlgdata = showModalDialog( "dhlib/dlgLink1.html", dlgdata, "dialogWidth:580px; dialogHeight:180px;status:no;help:no");
	if (dlgdata==null) return;
	
	var str = dlgdata["url"];
	if (str=="http://" || str=="") return;

	if (a) {    	
		a.href = str;
	}
	else { 
	  	editPane.execCommand("CreateLink", str);
		a = editpaneFindAncestorElement("A", editPane.getSelectedElement(rg));
		if (a) a.className = "BodyLink";
	}
	
}

/**
	Toolbar action handler called when corresponding icon is pressed.

  	Parameters: 
		editPane		The CEditpane object wrapping the editable element.
		rg					A range corresponding to the current selection.
		sType			The type of selection ("None/Text/Control").
	 
*/
function toolbarActionInsertCharacter(editPane, rg, sType) 
{ 
	if (sType=="Control") return;

	var entity = showModalDialog( "dhlib/dlgCharacters.html", "", "dialogWidth:280px; dialogHeight:250px;status:no;help:no");
	if (entity==null) return;

	entity = "&"+entity+";";
	
  	rg.pasteHTML(entity);
}

/**
	Toolbar action handler called when corresponding icon is pressed.

  	Parameters: 
		editPane		The CEditpane object wrapping the editable element.
		rg					A range corresponding to the current selection.
		sType			The type of selection ("None/Text/Control").
	 
*/
function toolbarActionCreateRule(editPane, rg, sType) 
{ 
	editPane.execCommand("inserthorizontalrule");
}

/**
	Toolbar action handler called when corresponding icon is pressed.

  	Parameters: 
		editPane		The CEditpane object wrapping the editable element.
		rg					A range corresponding to the current selection.
		sType			The type of selection ("None/Text/Control").
	 
*/
function toolbarActionProperties(editPane, rg, sType) 
{ 
	var cmp = editPane.getSelectedComponent();
//	cmp.setSelected();
	cmp.showProperties();
}

/**
	Toolbar action handler called when corresponding icon is pressed.

  	Parameters: 
		editPane		The CEditpane object wrapping the editable element.
		rg					A range corresponding to the current selection.
		sType			The type of selection ("None/Text/Control").
	 
*/
function toolbarActionForeColor(editPane, rg, sType) 
{ 
	alert("Not implemented");
}

/**
	Toolbar action handler called when corresponding icon is pressed.

  	Parameters: 
		editPane		The CEditpane object wrapping the editable element.
		rg					A range corresponding to the current selection.
		sType			The type of selection ("None/Text/Control").
	 
*/
function toolbarActionBackColor(editPane, rg, sType) 
{ 
	alert("Not implemented");
}

/**
	Toolbar action handler called when corresponding icon is pressed.

  	Parameters: 
		editPane		The CEditpane object wrapping the editable element.
		rg					A range corresponding to the current selection.
		sType			The type of selection ("None/Text/Control").
	 
*/
function toolbarActionCreateTable(editPane, rg, sType) 
{ 
	var dlgdata = null;

	dlgdata = showModalDialog( "dhlib/dlgTable1.html", dlgdata, "dialogWidth:17em; dialogHeight:10em; status:no");
	if (dlgdata==null) return;

	var nRows = parseInt(dlgdata["rows"]);
	var nCols = parseInt(dlgdata["cols"]);
	
	m_editpaneInsertTable(nRows, nCols);
}

/**
	Toolbar action handler called when corresponding icon is pressed.

  	Parameters: 
		editPane		The CEditpane object wrapping the editable element.
		rg					A range corresponding to the current selection.
		sType			The type of selection ("None/Text/Control").
	 
*/
function toolbarActionInsertRow(editPane, rg, sType) 
{ 
	
	
	
	m_editpaneInsertRow();


}

/**
	Toolbar action handler called when corresponding icon is pressed.

  	Parameters: 
		editPane		The CEditpane object wrapping the editable element.
		rg					A range corresponding to the current selection.
		sType			The type of selection ("None/Text/Control").
	 
*/
function toolbarActionUpdate(editPane, rg, sType) 
{  
	var fm = document.forms[0];
	if (fm==null) return;
	
	window._ActionPostInProgress = 1; /////////////////////
	if (fm.onsubmit) if (fm.onsubmit()==false) return;

	fm.submit();
}

/**
	Toolbar action handler called when corresponding icon is pressed.

  	Parameters: 
		editPane		The CEditpane object wrapping the editable element.
		rg					A range corresponding to the current selection.
		sType			The type of selection ("None/Text/Control").
	 
*/
function toolbarActionSource(editPane, rg, sType) 
{ 
	if (editPane.isSourceMode()) 
		editPane.setSourceMode(false);
	else
		editPane.setSourceMode(true);
}


/*------------------------------------------------------------------------*/
/*	Event Handlers                                                           */
/*------------------------------------------------------------------------*/

/**
	Handle onmouseover and onmouseup.
	
	Owning Elements:
		Handler is set on the img tag of each action bar button.
		
	Source Elements:
		Source element will the img tag itself.
*/
function e_toolbarBtnMouseOver() 
{
	if (this!=event.srcElement) return;
    with (event.srcElement.style) {
		borderBottom = "buttonshadow 1px solid";
		borderLeft = "buttonhighlight 1px solid";
		borderRight = "buttonshadow 1px solid";
		borderTop =  "buttonhighlight 1px solid";
	}
 	event.cancelBubble=true;
  	return false;
}

/**
	Handle onmouseout.
	
	Owning Elements:
		Handler is set on the img tag of each action bar button.
		
	Source Elements:
		Source element will the img tag itself.
*/
function e_toolbarBtnMouseOut() 
{
    with (event.srcElement.style) {
		borderBottom = "buttonface 1px solid";
		borderLeft = "buttonface 1px solid";
		borderRight = "buttonface 1px solid";
		borderTop = "buttonface 1px solid";
	}
}

/**
	Handle onmousedown.
	
	Owning Elements:
		Handler is set on the img tag of each action bar button.
		
	Source Elements:
		Source element will the img tag itself.
*/
function e_toolbarBtnMouseDown() 
{
    with (event.srcElement.style) {
		borderBottom = "buttonhighlight 1px solid";
		borderLeft = "buttonshadow 1px solid";
		borderRight = "buttonhighlight 1px solid";
		borderTop = "buttonshadow 1px solid";
	}
  	return false;
}


/**
	Handle onclick for a toolbar item.
	
	Owning Elements:
		Handler is set on the img tag of each action bar button.
		
	Source Elements:
		Source element will the img tag itself.
*/
function e_toolbarClick() 
{
	/*
		Get the toolbar img element on which the handler is being called.
	*/
	var itm = this;

	/*
		Get the toolbar object.
	*/
	var toolbar = itm._toolbar;
	if (toolbar==null) return false;

	/*
		Get the CEditPane object.
	*/
	var editPane = toolbar.editPane

	/*
		Get the action function associated with this toolbar item.
	*/
	var action = itm._toolbarAction

	/*
		Check that the cursor is inside the edit pane and not somewhere else on 
		the page. Skip this test for the Save button.
	*/
	if (action!=toolbarActionUpdate) {
		var rg = editPane.getSelectedRange();
		if (rg==null) return false;
	}

	/*
		Call the action function.
	*/
	if (action) action(editPane, rg, document.selection.type);

  	editPane.focus();
}




/**
	Add a (purely decorative) handle to the toolbar.

  	Parameters: 
  		None
*/
function m_toolbarAddHandle()
{ 
	var e = document.createElement("span");
	e.unselectable="On"; 

	with (e.style) {
		backgroundColor = "buttonface";
		borderLeft = "buttonhighlight 1px solid";
		borderRight = "buttonshadow 1px solid";
		borderTop = "buttonhighlight 1px solid";
		fontSize = "1px";
		height = "23px";
		width = "3px";
		marginRight = "3px";
	}

	this.element.appendChild(e);
}

/**
	Add a separator handle to the toolbar.

  	Parameters: 
  		None	 
*/
function m_toolbarAddSeparator()
{ 

	var e = document.createElement("span");
	e.unselectable="On"; 
	
	with (e.style) {
		borderLeft = "buttonshadow 1px solid";
		borderRight ="buttonhighlight 1px solid";
		fontSize = "0px";
		height = "23px";
		width = "1px";
		marginRight = "4px";
	}

	this.element.appendChild(e);
}

/**
	Add a an action button to the toolbar.

  	Parameters: 
  		label		The tooltip text for the button	 
  		icon		The icon image url	 
  		action	The fucntion to be called when the button is clicked	 
*/
function m_toolbarAddButton(label, icon, action)
{
	/*
		Create and format a new span element.
	*/
	var e = document.createElement("span");
	e.title = label;
	e.unselectable="On"; 
	e.style.height = "23px";
	e.style.width = "23px";

	/*
		Create and format the image element to display the icon.
	*/
	var img = document.createElement("img");
	with (img.style) {
		backgroundColor = "buttonface";
		borderBottom = "buttonface 1px solid";
		borderLeft = "buttonface 1px solid";
		borderRight = "buttonface 1px solid";
		borderTop = "buttonface 1px solid";
		marginRight = "3px";
	}

	/*
		Set up the required attributes and event handlers.
	*/
	with (img) {
		src = icon;
		unselectable="On"; 
		onmouseover = e_toolbarBtnMouseOver;
		onmouseout = e_toolbarBtnMouseOut;
		onmousedown = e_toolbarBtnMouseDown;
		onmouseup = e_toolbarBtnMouseOver;
		onclick = e_toolbarClick;
	}

	/*
		Store pointers to items to be used in the event handlers.
	*/
	img._toolbar = this; 
	img._toolbarAction = action;


	/*
		Add the new elements into the document.
	*/
	e.appendChild(img);
	this.element.appendChild(e);
}

/**
	Construct the toolbar.

  	Parameters: 
  		None
*/
function m_toolbarBuildBar()
{ 
	with(this) {
		addHandle();
//		addButton("Cut", EDITPANE_BASE+"images/cut.gif", toolbarActionCut);
		addButton("Copy", EDITPANE_BASE+"images/copy.gif", toolbarActionCopy);
		addButton("Paste", EDITPANE_BASE+"images/paste.gif", toolbarActionPaste);
		addSeparator();
		addButton("Bold", EDITPANE_BASE+"images/bold.gif", toolbarActionBold);
		addButton("Italic", EDITPANE_BASE+"images/italic.gif", toolbarActionItalic);
		addButton("Underline", EDITPANE_BASE+"images/under.gif", toolbarActionUnderline);
		addSeparator();
		addButton("Align Left", EDITPANE_BASE+"images/aleft.gif", toolbarActionLeft);
		addButton("Center", EDITPANE_BASE+"images/center.gif", toolbarActionCenter);
		addButton("Align Right", EDITPANE_BASE+"images/aright.gif", toolbarActionRight);
		addSeparator();
		addButton("Numbered List", EDITPANE_BASE+"images/nlist.gif", toolbarActionOList);
		addButton("Bulletted List", EDITPANE_BASE+"images/blist.gif", toolbarActionUList);
		addSeparator();
		addButton("Create Link", EDITPANE_BASE+"images/wlink.gif", toolbarActionCreateLink);
		addSeparator();
		addButton("Horizontal Rule", EDITPANE_BASE+"images/tool_line.gif", toolbarActionCreateRule);
		addSeparator();
		addButton("Insert Special Character", EDITPANE_BASE+"images/fgcolor.gif", toolbarActionInsertCharacter);
		addSeparator();
		addButton("Insert Table", EDITPANE_BASE+"images/instable.gif", toolbarActionCreateTable);
		addButton("Insert Row", EDITPANE_BASE+"images/insrow.gif", toolbarActionInsertRow);
		addSeparator();
		addButton("Poperties", EDITPANE_BASE+"images/props.gif", toolbarActionProperties);
		addSeparator();
		addButton("Show/Hide Source", EDITPANE_BASE+"images/newdoc.gif", toolbarActionSource);
//		addSeparator();
//		addButton("Save Changes", EDITPANE_BASE+"images/save.gif", toolbarActionUpdate);
	}
}



function CEditpaneToolbar(idToolbar, oEditpane)
{ 
	this.element = document.getElementById(idToolbar);
	if (this.element==null) {
		alert("Invalid ID "+idToolbar+"passed to CEditpaneToolbar constructor");
		return;
	}

	this.editPane = oEditpane;
	this.addHandle = m_toolbarAddHandle;		
	this.addSeparator = m_toolbarAddSeparator;		
	this.addButton = m_toolbarAddButton;		
	this.buildBar = m_toolbarBuildBar;

  with(this.element.style)
  {
  	backgroundColor = "buttonface";
	borderBottom = "buttonshadow 1px solid";
	borderLeft ="buttonhighlight 1px solid";
	borderRight = "buttonshadow 1px solid";
	borderTop = "buttonhighlight 1px solid";
	height = "30px";
	paddingTop = "3px";
	paddingBottom = "3px";
	
  }

	this.element.unselectable="On"; 
	
  	this.buildBar();
	
  	document.execCommand("2D-Position", false, false);
  	document.execCommand("LiveResize", false, true);
  	document.execCommand("MultipleSelection", false, false);
}







function editcmpArefAlignLeft(cmp)
{
	var top = cmp.getTopElement(); 
	top.align="left";
	top.style.width="";
	top.style.marginTop = "0pt";
	top.style.marginBottom = "5pt";
	top.style.marginLeft = "0pt";
	top.style.marginRight = "5pt";
}

function editcmpArefAlignRight(cmp)
{
	var top = cmp.getTopElement(); 
	top.align="right";
	top.style.width="";
	top.style.marginTop = "0pt";
	top.style.marginBottom = "5pt";
	top.style.marginLeft = "5pt";
	top.style.marginRight = "0pt";
}

function editcmpArefAlignCenter(cmp) 
{
	var top = cmp.getTopElement(); 
	top.align="";
	top.style.width="96%";
	top.style.margin = "5pt 0pt 5pt 0pt";
}

function editcmpArefMakeThumbnail(cmp) 
{
	var img = cmp.element;
	var a = editpaneFindAncestorElement("A", img); 
	if (a==null) {
		a = document.createElement("A");
		a.href = img.src;
		img.parentElement.insertBefore(a, img);
		a.appendChild(img);
	}
	else {
		a.href = img.src;
	}
}


function m_editcmpArefGetTopElement()
{
	var top = editpaneFindAncestorElement("TABLE", this.element); 
	if (top==null||!editpaneIsComponentElement(top)) {
		 alert("Iconsistent component structure");
		 return null;
	}
	return top;
}


function m_editcmpArefSelectTopElement()
{
	var rg= document.body.createControlRange()
	
	var top = this.getTopElement();
	
	//rg.remove(0);
	rg.addElement(top);
	rg.select();	

	return true;
}

function m_editcmpArefRemove()
{
	this.getTopElement.removeNode(true);
}

function m_editcmpArefBeforeDelete()
{
	if (document.selection.type!="Control") return;
	this.selectTopElement();
}

function m_editcmpArefContextmenu(x, y)
{
	var menu = window.editpaneContextmenuAref;
	
	if (menu==null) {
		menu = new CContextMenu();
		menu.addItem("Align left", editcmpArefAlignLeft);
		menu.addItem("Align center", editcmpArefAlignCenter);
		menu.addItem("Align right", editcmpArefAlignRight);
		menu.addSeparator();
		menu.addItem("Make thumbnail", editcmpArefMakeThumbnail);
		window.editpaneContextmenuAref = menu;
	}
	
	document.selection.empty()
	
	menu.show(this, x, y);
	
	return false;
}


function m_editcmpArefProperties()
{
	var dlgdata = new Array();
	
	var w = this.element.style.width;
	var h= this.element.style.height;
	
	dlgdata["width"] = w;
	if (w=="") w = this.element.width;
	dlgdata["height"] = h;
	if (h=="") h = this.element.height;

	dlgdata = showModalDialog( "dhlib/dlgArefProperties.html", dlgdata, "dialogWidth:17em; dialogHeight:10em; status:no");
	if (dlgdata==null) return;

	w =dlgdata["width"];
	h = dlgdata["height"];
	
	this.element.style.width = w;
	this.element.style.height = h;
	
	return false;
}


function m_editcmpArefSetSelected()
{
    var oControlRange = document.body.createControlRange();
    oControlRange.add(this.element);
    oControlRange.select();	
}


function m_editcmpTablGetTopElement()
{
	var top = editpaneFindAncestorElement("TABLE", this.element); 
	return top;
}


function m_editcmpTablSelectTopElement()
{
	var rg= document.body.createControlRange()
	
	var top = this.getTopElement();
	
	//rg.remove(0);
	rg.addElement(top);
	rg.select();	

	return true;
}

function m_editcmpTablSetSelected()
{
	this.selectTopElement();
	/*
    var oControlRange = document.body.createControlRange();
    oControlRange.add(this.element);
    oControlRange.select();	*/
}


function m_editcmpTablProperties()
{
	var dlgdata = new Array();

	var e = this.getTopElement();

	dlgdata["class"] = e.className;

	dlgdata = showModalDialog( "dhlib/dlgTablProperties.html", dlgdata, "dialogWidth:450px; dialogHeight:200px; status:no");
	if (dlgdata==null) return;

	e.className = dlgdata["class"];
	
	var borders = dlgdata["borders"];
	if (borders=="grid") {
		e.style.border = "1px solid black"
		for (var n=0; n<e.cells.length; n++) { e.cells.item(n).style.border = "1px solid black"}
	}
	else if (borders=="box") {
		e.style.border = "1px solid black"
		for (var n=0; n<e.cells.length; n++) { e.cells.item(n).style.borderStyle = "none"}
	}
	else if (borders=="outline") {
		e.style.borderStyle = "none"
		for (var n=0; n<e.cells.length; n++) { e.cells.item(n).style.borderStyle = "none"}
		var row = e.rows.item(0);
		for (n=0; n<row.cells.length; n++) { row.cells.item(n).style.borderBottom = "1px solid black"}
		row = e.rows.item(e.rows.length-1);
		for (n=0; n<row.cells.length; n++) { row.cells.item(n).style.borderBottom = "1px solid black"}
	}
	else if (borders=="none") {
		e.style.borderStyle = "none"
		for (var n=0; n<e.cells.length; n++) { e.cells.item(n).style.borderStyle = "none"}
	}

	return false;
}



function CEditpaneComponent(e)
{
	var fnNoop = new Function("return true"); /////////////////////////////////////////////////
	this.showContextMenu = fnNoop;
	this.showProperties = fnNoop;
	this.getTopElement = fnNoop;
	this.setSelected = fnNoop;
	this.remove = fnNoop;
	this.selectTopElement = fnNoop;
	this.beforeDelete = fnNoop;
	if (e==null) return;

	this.element = e;

	var id = e.id;
	if (id==null) return;
	
	var sType;
	if (id.substr(0,4)!=EDITPANE_ID_PREFIX) 
		sType = "ELEM_"+ e.tagName;
	else
		sType = id.substr(4,4);
	
	switch (sType) {
		case "AREF":
			this.showContextMenu = m_editcmpArefContextmenu;
			this.showProperties = m_editcmpArefProperties;
			this.getTopElement = m_editcmpArefGetTopElement;
			this.remove = m_editcmpArefRemove;
			this.setSelected = m_editcmpArefSetSelected;
			this.selectTopElement = m_editcmpArefSelectTopElement;
			this.beforeDelete = m_editcmpArefBeforeDelete;
			break;
		case "LINK": 
			break;
		case "TABL": 
			this.showProperties = m_editcmpTablProperties;
			this.getTopElement = m_editcmpTablGetTopElement;
			this.setSelected = m_editcmpTablSelectTopElement;
			this.selectTopElement = m_editcmpTablSelectTopElement;
			break;
		case "ELEM_IMG": 
			this.showProperties = m_editcmpArefProperties;
			break;
	}
}

