// Table Operations Plugin for HTMLArea-3.0
// Implementation by Mihai Bazon.  Sponsored by http://www.bloki.com
//
// htmlArea v3.0 - Copyright (c) 2002 interactivetools.com, inc.
// This notice MUST stay intact for use (see license.txt).
//
// A free WYSIWYG editor replacement for <textarea> fields.
// For full source code and docs, visit http://www.interactivetools.com/
//
// Version 3.0 developed by Mihai Bazon for InteractiveTools.
//   http://dynarch.com/mishoo
//
// $Id: table-operations.js,v 1.16 2009/06/09 22:08:46 ajain Exp $

// Object that will encapsulate all the table operations provided by
// HTMLArea-3.0 (except "insert table" which is included in the main file)
TableOperations.I18N = tableOperationsI18n;

function TableOperations(editor) {
	this.editor = editor;
    var tablecopy;
    var tablecopynode;
	var cfg = editor.config;
	var tt = TableOperations.I18N;
	var bl = TableOperations.btnList;
	var self = this;

	// register the toolbar buttons provided by this plugin
	var toolbar = ["linebreak"];
	for (var i in bl) {
		var btn = bl[i];
		if (!btn) {
			toolbar.push("separator");
		} else {
			var id = "TO-" + btn[0];
			var extension = ".gif";
			
			cfg.registerButton(id, tt[id], editor.imgURL(btn[0] + extension, "TableOperations"), false,
					   function(editor, id) {
						   // dispatch button press event
						   self.buttonPress(editor, id);
					   }, btn[1]);
			toolbar.push(id);
		}
	}
	// add a new line in the toolbar
	if(cfg.toolbar.push)
	{
	    if (editor.toggleMode == 1)
	    {
			cfg.toolbar.push(toolbar);
		}
	}
};

TableOperations._pluginInfo = {
	name          : "TableOperations",
	version       : "1.0",
	developer     : "Mihai Bazon",
	developer_url : "http://dynarch.com/mishoo/",
	c_owner       : "Mihai Bazon",
	sponsor       : "Zapatec Inc.",
	sponsor_url   : "http://www.bloki.com",
	license       : "htmlArea"
};

/************************
 * UTILITIES
 ************************/

// retrieves the closest element having the specified tagName in the list of
// ancestors of the current selection/caret.
TableOperations.prototype.getClosest = function(tagName) {
	var editor = this.editor;
	var ancestors = editor.getAllAncestors();
	var ret = null;
	tagName = ("" + tagName).toLowerCase();
	for (var i in ancestors) {
		var el = ancestors[i];
		if (el.tagName.toLowerCase() == tagName) {
			ret = el;
			break;
		}

	}
	
	return ret;
};

function getNextTable(node)
{
	
	 var obj = node.nextSibling;
	 if(obj.nodeType == 3)
	 {
		obj = obj.nextSibling;  
	 }
	 if((obj.tagName).toLowerCase() != "table")
	 {
		 obj = getNextTable(obj);
		 return obj;
	 }
	 /*
	 if((obj.tagName).toLowerCase() == "br" ||(obj.tagName).toLowerCase() == "p")
	 {
	   if((obj.tagName).toLowerCase() == "br")
	   {
		 obj = getNextTable(obj);
		 return obj;
	   }
	   if((obj.tagName).toLowerCase() == "p")
	   {
		 if(obj.innerHTML == "")
		 {
			obj = getNextTable(obj);
			return obj;
		 }
		 else
		 {
			 return obj;
		 }
	   }
	 }
	 */
	 return obj;
}
// this function requires the file PopupDiv/PopupWin to be loaded from browser
TableOperations.prototype.dialogTableProperties = function() {
	var i18n = TableOperations.I18N;
	// retrieve existing values
	var table = this.getClosest("table");
	// this.editor.selectNodeContents(table);
	// this.editor.updateToolbar();

	var dialog = new PopupWin(this.editor, i18n["Table Properties"], function(dialog, params) {
	
		if(params["f_st_borderStyle"] == "none")
		{
		  params["f_st_borderWidth"]  = "0";
		}

		if(params["f_st_borderWidth"] == "0")
		{
		  params["f_st_borderStyle"]  = "none";
		}
		
		TableOperations.processStyle(params, table);

		for (var i in params) {
			var val = params[i];
			switch (i) {
			    case "f_caption":
				if (/\S/.test(val)) {
					// contains non white-space characters
					var caption = table.getElementsByTagName("caption")[0];
					if (!caption) {
						caption = dialog.editor._doc.createElement("caption");
						table.insertBefore(caption, table.firstChild);
					}
					caption.innerHTML = val;
				} else {
					// search for caption and delete it if found
					var caption = table.getElementsByTagName("caption")[0];
					if (caption) {
						caption.parentNode.removeChild(caption);
					}
				}
			
				break;
			    case "f_summary":
				table.summary = val;
				break;
			    case "f_width":
				table.style.width = ("" + val) + params.f_unit;
				break;
			    case "f_align":
				table.align = val;
				break;
			    case "f_spacing":
				table.cellSpacing = val;
				break;
			    case "f_padding":
				table.cellPadding = val;
				break;
			    case "f_borders":
				table.border = val;
				break;
			    
			}
		}
	
		// various workarounds to refresh the table display (Gecko,
		// what's going on?! do not disappoint me!)
		
		dialog.editor.forceRedraw();
		dialog.editor.focusEditor();
		dialog.editor.updateToolbar();
		var save_collapse = table.style.borderCollapse;
		table.style.borderCollapse = "collapse";
		table.style.borderCollapse = "separate";
		table.style.borderCollapse = save_collapse;
		
	},

	// this function gets called when the dialog needs to be initialized
	function (dialog) {

		var f_caption = "";
		var capel = table.getElementsByTagName("caption")[0];
		if (capel) {
			f_caption = capel.innerHTML;
		}
		var f_summary = table.summary;
		var f_width = parseInt(table.style.width);
		isNaN(f_width) && (f_width = "");
		
		var f_unit = "";
		if(/%/.test(table.style.width))
		{
			f_unit="percent";
		}
		else if(/px/.test(table.style.width))
		{
			  f_unit="pixels";
		}
		else if(/pt/.test(table.style.width))
		{
			  f_unit="points";
		}
		var f_align = table.align;
		var f_spacing = table.cellSpacing;
		var f_padding = table.cellPadding;
		var f_borders = table.border;
		var f_frames = table.frame;
		var f_rules = table.rules;

		function selected(val) {
			return val ? " selected" : "";
		};

		// dialog contents
		dialog.content.style.width = "400px";
		dialog.content.innerHTML = " \
		<div class='title'\>" + i18n["Table Properties"] + "</div> \
<table style='width:100%'> \
  <tr> \
    <td> \
      <fieldset><legend>" + i18n["Description"] + "</legend> \
       <table style='width:100%'> \
        <tr> \
          <td class='label'>" + i18n["Caption"] + ":</td> \
          <td class='value'><input type='text' name='f_caption' value='" + f_caption + "'/></td> \
        </tr><tr> \
          <td class='label'>" + i18n["Summary"] + ":</td> \
          <td class='value'><input type='text' name='f_summary' value='" + f_summary + "'/></td> \
        </tr> \
       </table> \
      </fieldset> \
    </td> \
  </tr> \
  <tr><td id='--HA-layout'></td></tr> \
  <tr> \
    <td> \
      <fieldset><legend>" + i18n["Spacing and padding"] + "</legend> \
       <table style='width:100%'> \
"+//        <tr> \
//           <td class='label'>" + i18n["Width"] + ":</td> \
//           <td><input type='text' name='f_width' value='" + f_width + "' size='5' /> \
//             <select name='f_unit'> \
//               <option value='%'" + selected(f_unit == "percent") + ">" + i18n["percent"] + "</option> \
//               <option value='px'" + selected(f_unit == "pixels") + ">" + i18n["pixels"] + "</option> \
//             </select> &nbsp;&nbsp;" + i18n["Align"] + ": \
//             <select name='f_align'> \
//               <option value='left'" + selected(f_align == "left") + ">" + i18n["Left"] + "</option> \
//               <option value='center'" + selected(f_align == "center") + ">" + i18n["Center"] + "</option> \
//               <option value='right'" + selected(f_align == "right") + ">" + i18n["Right"] + "</option> \
//             </select> \
//           </td> \
//         </tr> \
"        <tr> \
          <td class='label'>" + i18n["Spacing"] + ":</td> \
          <td><input type='text' name='f_spacing' size='5' value='" + f_spacing + "' /> &nbsp;" + i18n["Padding"] + ":\
            <input type='text' name='f_padding' size='5' value='" + f_padding + "' /> &nbsp;&nbsp;" + i18n["pixels"] + "\
          </td> \
        </tr> \
		</table> \
      </fieldset> \
    </td> \
  </tr> \
"+//  <tr> \
 //   <td> \
 //     <fieldset><legend>Frame and borders</legend> \
 //       <table width='100%'> \
 //         <tr> \
 //           <td class='label'>" + i18n["Borders"] + ":</td> \
 //           <td><input name='f_borders' type='text' size='5' value='" + f_borders + "' /> &nbsp;&nbsp;" + i18n["pixels"] + "</td> \
 //    </tr> \
 //         <tr> \
 //           <td class='label'>" + i18n["Frames"] + ":</td> \
 //           <td> \
 //             <select name='f_frames'> \
 //               <option value='void'" + selected(f_frames == "void") + ">" + i18n["No sides"] + "</option> \
 //               <option value='above'" + selected(f_frames == "above") + ">" + i18n["The top side only"] + "</option> \
 //               <option value='below'" + selected(f_frames == "below") + ">" + i18n["The bottom side only"] + "</option> \
 //               <option value='hsides'" + selected(f_frames == "hsides") + ">" + i18n["The top and bottom sides only"] + "</option> \
 //               <option value='vsides'" + selected(f_frames == "vsides") + ">" + i18n["The right and left sides only"] + "</option> \
 //               <option value='lhs'" + selected(f_frames == "lhs") + ">" + i18n["The left-hand side only"] + "</option> \
 //               <option value='rhs'" + selected(f_frames == "rhs") + ">" + i18n["The right-hand side only"] + "</option> \
 //             <option value='box'" + selected(f_frames == "box") + ">" + i18n["All four sides"] + "</option> \
 //           </select> \
 //         </td> \
 //       </tr> \
 //      <tr> \
 //         <td class='label'>" + i18n["Rules"] + ":</td> \
 //         <td> \
 //           <select name='f_rules'> \
 //             <option value='none'" + selected(f_rules == "none") + ">" + i18n["No rules"] + "</option> \
 //             <option value='rows'" + selected(f_rules == "rows") + ">" + i18n["Rules will appear between rows only"] + "</option> \
 //             <option value='cols'" + selected(f_rules == "cols") + ">" + i18n["Rules will appear between columns only"] + "</option> \
 //             <option value='all'" + selected(f_rules == "all") + ">" + i18n["Rules will appear between all rows and columns"] + "</option> \
 //           </select> \
 //         </td> \
 //       </tr> \
 //     </table> \
 //   </fieldset> \
 // </td> \
 // </tr>
 "        <tr> \
    <td id='--HA-style'></td> \
  </tr> \
</table> \
";
		var st_prop = TableOperations.createStyleFieldset(dialog.doc, dialog.editor, table);
		var p = dialog.doc.getElementById("--HA-style");
		p.appendChild(st_prop);
		var st_layout = TableOperations.createStyleLayoutFieldset(dialog.doc, dialog.editor, table);
		p = dialog.doc.getElementById("--HA-layout");
		p.appendChild(st_layout);
		dialog.modal = true;
		dialog.addButtons("ok", "cancel");
		dialog.showAtElement(dialog.editor._iframe, "c");
		try
		{
			var val = (/collapse/i.test(table.style.borderCollapse));
			if(val)
			{
				dialog.doc.getElementById("f_st_borderCollapse").checked=true;
			}
			else
			{
				dialog.doc.getElementById("f_st_borderCollapse").checked=false;
			}
						
		}catch(err){}

		try
		{
			var val = table.__msh_globalStyle;
			if(val == true)
			{
				dialog.doc.getElementById("f_our_globalStyle").checked=true;
			}
			else if(val == false)
			{
				dialog.doc.getElementById("f_our_globalStyle").checked=false;
			}
			else
			{
			   dialog.doc.getElementById("f_our_globalStyle").checked=true;
			}
						
		}catch(err){}
	 },500,400);
};

// this function requires the file PopupDiv/PopupWin to be loaded from browser
TableOperations.prototype.dialogRowCellProperties = function(cell,rowsorcells) {
	var i18n = TableOperations.I18N;
	// retrieve existing values
	var element = this.getClosest(cell ? "td" : "tr");
	var table = this.getClosest("table");
	// this.editor.selectNodeContents(element);
	// this.editor.updateToolbar();
	if(rowsorcells.length == 0)
	{			
		rowsorcells.push(element);
	}
	var dialog = new PopupWin(this.editor, i18n[cell ? "Cell Properties" : "Row Properties"], function(dialog, params) {
		var roworcell =null;
		for(var j=0;j<rowsorcells.length;j++)
		{
		   roworcell = rowsorcells[j];

		  
		   TableOperations.processStyle(params, roworcell);
		
			for (var i in params) {
				var val = params[i];
				switch (i) {
					case "f_align":
					roworcell.align = val;
					break;
					case "f_char":
					roworcell.ch = val;
					break;
					case "f_valign":
					roworcell.vAlign = val;
					break;
				}
			}
		}
		// various workarounds to refresh the table display (Gecko,
		// what's going on?! do not disappoint me!)
		dialog.editor.forceRedraw();
		dialog.editor.focusEditor();
		dialog.editor.updateToolbar();
		var save_collapse = table.style.borderCollapse;
		table.style.borderCollapse = "collapse";
		table.style.borderCollapse = "separate";
		table.style.borderCollapse = save_collapse;
	},

	// this function gets called when the dialog needs to be initialized
	function (dialog) {

		var f_align = element.align;
		var f_valign = element.vAlign;
		var f_char = element.ch;

		function selected(val) {
			return val ? " selected" : "";
		};

		// dialog contents
		dialog.content.style.width = "400px";
		dialog.content.innerHTML = " \
<div class='title'\>" + i18n[cell ? "Cell Properties" : "Row Properties"] + "</div> \
<table style='width:100%'> \
  <tr> \
    <td id='--HA-layout'> \
"+//      <fieldset><legend>" + i18n["Layout"] + "</legend> \
//        <table style='width:100%'> \
//         <tr> \
//           <td class='label'>" + i18n["Align"] + ":</td> \
//           <td> \
//             <select name='f_align'> \
//               <option value='left'" + selected(f_align == "left") + ">" + i18n["Left"] + "</option> \
//               <option value='center'" + selected(f_align == "center") + ">" + i18n["Center"] + "</option> \
//               <option value='right'" + selected(f_align == "right") + ">" + i18n["Right"] + "</option> \
//               <option value='char'" + selected(f_align == "char") + ">" + i18n["Char"] + "</option> \
//             </select> \
//             &nbsp;&nbsp;" + i18n["Char"] + ": \
//             <input type='text' style='font-family: monospace; text-align: center' name='f_char' size='1' value='" + f_char + "' /> \
//           </td> \
//         </tr><tr> \
//           <td class='label'>" + i18n["Vertical align"] + ":</td> \
//           <td> \
//             <select name='f_valign'> \
//               <option value='top'" + selected(f_valign == "top") + ">" + i18n["Top"] + "</option> \
//               <option value='middle'" + selected(f_valign == "middle") + ">" + i18n["Middle"] + "</option> \
//               <option value='bottom'" + selected(f_valign == "bottom") + ">" + i18n["Bottom"] + "</option> \
//               <option value='baseline'" + selected(f_valign == "baseline") + ">" + i18n["Baseline"] + "</option> \
//             </select> \
//           </td> \
//         </tr> \
//        </table> \
//       </fieldset> \
"    </td> \
  </tr> \
  <tr> \
    <td id='--HA-style'></td> \
  </tr> \
</table> \
";		
		var st_prop;
		if(cell)
			st_prop = TableOperations.createStyleFieldset(dialog.doc, dialog.editor, element);
		else
			st_prop = TableOperations.createStyleFieldset(dialog.doc, dialog.editor, element);
		var p = dialog.doc.getElementById("--HA-style");
		p.appendChild(st_prop);
		var st_layout = TableOperations.createStyleLayoutFieldset(dialog.doc, dialog.editor, element);
		p = dialog.doc.getElementById("--HA-layout");
		p.appendChild(st_layout);
		dialog.modal = true;
		dialog.addButtons("ok", "cancel");
		dialog.showAtElement(dialog.editor._iframe, "c");
	},280,400);
};

// this function gets called when some button from the TableOperations toolbar
// was pressed.
TableOperations.prototype.buttonPress = function(editor, button_id) {
	this.editor = editor;
	var mozbr = HTMLArea.is_gecko ? "<br />" : "";
	var i18n = TableOperations.I18N;

	// helper function that clears the content in a table row
	function clearRow(tr) {
		var tds = tr.getElementsByTagName("td");
		for (var i = tds.length; --i >= 0;) {
			var td = tds[i];
			td.rowSpan = 1;
			td.innerHTML = mozbr;
		}
	};

	function removeAllAttributes(element)
	{
		try
		{
			var arAttributes = element.attributes;
			if(arAttributes!=null && arAttributes.length>0)
			{
				var names = new Array();
				for(var attr=0;attr<element.attributes.length;attr++)
				{
						names.push(element.attributes[attr].nodeName);
				}
				for(attr=0;attr<names.length;attr++)
				{
					/**if(/valign|cellspacing|cellpadding/.test(names[attr].toLowerCase())) 
					{
						continue;
					}**/
					element.removeAttribute(names[attr]);
				}
				element.removeAttribute("className");
			}
		}
		catch(err){}
	};

	function cleanTable(elTable)
	{
		/** Remove col groups **/
		var colgrp = elTable.getElementsByTagName("COLGROUP");
		if(colgrp!=null)
		{
				for (var c=0; c<colgrp.length; c++)
				{
					colgrp[c].parentNode.removeChild(colgrp[c]);
				}
		}
		/** Remove Table attributes **/
		removeAllAttributes(elTable);
		var rows = elTable.rows.length;
		if(rows>0)
		{
			for (var i=0; i<elTable.rows.length;i++)
			{
				var tr = elTable.rows[i];
				/** Remove TR attributes **/
				removeAllAttributes(tr);
				var cells = tr.cells.length;
				for (var j=0; j<tr.cells.length;j++)
				{
					var td = tr.cells[j];
					/** Remove TD attributes **/
					removeAllAttributes(td);
				}
			}
			alert("Action performed successfully.");
		}
	};


	function splitRow(td) {
		var n = parseInt("" + td.rowSpan);
		var nc = parseInt("" + td.colSpan);
		td.rowSpan = 1;
		tr = td.parentNode;
		var itr = tr.rowIndex;
		var trs = tr.parentNode.rows;
		var index = td.cellIndex;
		while (--n > 0) {
			tr = trs[++itr];
			var otd = td.cloneNode(false);
			otd.colSpan = td.colSpan;
			otd.innerHTML = mozbr;
			tr.insertBefore(otd, tr.cells[index]);
		}
		editor.forceRedraw();
		editor.updateToolbar();
	};

	function splitCol(td) {
		var nc = parseInt("" + td.colSpan);
		td.colSpan = 1;
		tr = td.parentNode;
		var ref = td.nextSibling;

		while (--nc > 0) {
			var otd = td.cloneNode(false);
			otd.rowSpan = td.rowSpan;
			otd.innerHTML = mozbr;
			tr.insertBefore(otd, ref);
		}
		editor.forceRedraw();
		editor.updateToolbar();
	};

	function splitCell(td) {
		var nc = parseInt("" + td.colSpan);
		splitCol(td);
		var items = td.parentNode.cells;
		var index = td.cellIndex;
		while (nc-- > 0) {
			splitRow(items[index++]);
		}
	};

	function selectNextNode(el) {
		var node = el.nextSibling;
		while (node && node.nodeType != 1) {
			node = node.nextSibling;
		}
		if (!node) {
			node = el.previousSibling;
			while (node && node.nodeType != 1) {
				node = node.previousSibling;
			}
		}
		if (!node) {
			node = el.parentNode;
		}
		editor.selectNodeContents(node);
	};

	function selectPreviousNode(el) {
		
		var node = el.previousSibling;
	
		while (node && node.nodeType != 1) {
			
			node = node.nextSibling;
		}
		if (!node) {
			node = el.previousSibling;
			while (node && node.nodeType != 1) {
				node = node.previousSibling;
			}
		}
		if (!node) {
			node = el.parentNode;
		}
		editor.selectNodeContents(node);
	};

	function getValidPreviousTR(tr) 
	{
		var newTR = tr.previousSibling;			
		
		if(newTR.nodeName == "#text")
		{
		   getValidPreviousTR(newTR) ;
		}				 
		else
		{
		  
		}
		return newTR;

	};

	switch (button_id) {
		// ROWS
		case "TO-move-row-up":
		var tr = this.getClosest("tr");
		if(tr)
		{
			var aboveTR = tr.previousSibling;
			if(aboveTR.nodeName == "#text")
			{
				aboveTR = aboveTR.previousSibling;
			}
			if(aboveTR)
			{
				var cloneTR = tr.cloneNode(true);
				var par = tr.parentNode;
				par.removeChild(tr);
				aboveTR.parentNode.insertBefore(cloneTR, aboveTR);
				selectPreviousNode(aboveTR);
			}
		}
		break;
		case "TO-move-row-down":
		var tr = this.getClosest("tr");
		if(tr)
		{
			var belowTR = tr.nextSibling;
			
			if(belowTR.nodeName == "#text")
			{
				belowTR = belowTR.nextSibling;
			}
			if(belowTR)
			{
				var cloneTR = tr.cloneNode(true);
				var par = tr.parentNode;
				par.removeChild(tr);
				belowTR.parentNode.insertBefore(cloneTR, belowTR.nextSibling);
				selectNextNode(belowTR);
			}
		}
		break;
	    case "TO-row-insert-above":
		case "TO-row-insert-under":
		var tr = this.getClosest("tr");
		if (!tr) {
			break;
		}
		var otr = tr.cloneNode(true);
		clearRow(otr);
		tr.parentNode.insertBefore(otr, /under/.test(button_id) ? tr.nextSibling : tr);
		editor.forceRedraw();
		editor.focusEditor();
		break;
		case "TO-row-copy-above":
		case "TO-row-copy-under":
		var tr = this.getClosest("tr");
		if (!tr) {
			break;
		}
		var otr = tr.cloneNode(true);
		tr.parentNode.insertBefore(otr, /under/.test(button_id) ? tr.nextSibling : tr);
		editor.forceRedraw();
		editor.focusEditor();
		break;
	    case "TO-row-delete":
		var tr = this.getClosest("tr");
		var sel = editor._getSelection();
		var range, i = 0;
		var row = null;
		var cells = [];
		if (!HTMLArea.is_ie) 
		{
			try 
			{
				while (range = sel.getRangeAt(i++)) {
					var td = range.startContainer.childNodes[range.startOffset];
					if (td.parentNode != row) {
						if(td && (td.tagName).toLowerCase() == "td")
						{
							cells.push(td.parentNode);
							row=td.parentNode;
						}
					}
				}
			} catch(e) {/* finished walking through selection */}
		
		}
		if(cells.length == 0)
		{
			cells.push(tr);
		}
		if(cells.length == 0)
		{
			break;
		}
		for(var j = 0 ; j < cells.length;j++)
		{
			var todeleterow =cells[j] 
			var par = todeleterow.parentNode;
			if (par.rows.length == 1) {
				alert(i18n["not-del-last-row"]);
				break;
			}
			// set the caret first to a position that doesn't
			// disappear.
			selectNextNode(todeleterow);
			par.removeChild(todeleterow);
		}

		editor.forceRedraw();
		editor.focusEditor();
		editor.updateToolbar();
		break;
	    case "TO-row-split":
		var td = this.getClosest("td");
		if (!td) {
			break;
		}
		splitRow(td);
		break;

		// COLUMNS

	    case "TO-col-insert-before":
	    case "TO-col-insert-after":
		var td = this.getClosest("td");
		if (!td) {
			break;
		}
		var rows = td.parentNode.parentNode.rows;
		var index = td.cellIndex;
		for (var i = rows.length; --i >= 0;) {
			var tr = rows[i];
			var ref = tr.cells[index + (/after/.test(button_id) ? 1 : 0)];
			var refStyle = tr.cells[index];
			var otd = refStyle.cloneNode(true);
			otd.innerHTML = mozbr;
			if(/before/.test(button_id))
			{
				tr.insertBefore(otd, ref);
			}
			else
			{
				if(HTMLArea.is_ie)
				{
				  refStyle.insertAdjacentElement("afterEnd",otd);
				}
				else
				{
					tr.insertBefore(otd, ref);
				}
			}
			
		}
		editor.focusEditor();
		break;
	    case "TO-col-split":
		var td = this.getClosest("td");
		if (!td) {
			break;
		}
		splitCol(td);
		break;
	    case "TO-col-delete":
		var td = this.getClosest("td");
		var sel = editor._getSelection();
		var range, i = 0;
		var row = null;
		var cells = [];
		if (!HTMLArea.is_ie) 
		{
			try {
				while (range = sel.getRangeAt(i++)) {
					var td1 = range.startContainer.childNodes[range.startOffset];
					
					if(td1 && (td1.tagName).toLowerCase() == "td")
						cells.push(td1);
				}
			} catch(e) {/* finished walking through selection */}
			
		}
		if(cells.length == 0)
		{
			cells.push(td);
		}
		if(cells.length == 0)
		{
			break;
		}
		for(var j = 0 ; j < cells.length;j++)
		{
			var todeletecol = cells[j];
			var index = todeletecol.cellIndex;
			if (todeletecol.parentNode.cells.length == 1) {
				alert(i18n["not-del-last-col"]);
				break;
			}
			// set the caret first to a position that doesn't disappear
			selectNextNode(todeletecol);
			var rows = todeletecol.parentNode.parentNode.rows;
			for (var i = rows.length; --i >= 0;) {
				var tr = rows[i];
				tr.removeChild(tr.cells[index]);
			}
		}
		editor.forceRedraw();
		editor.focusEditor();
		editor.updateToolbar();
		break;
		case "TO-table-delete":
		var table = this.getClosest("table");
		if (!table) {
			break;
		}
		var par = table.parentNode;
		// set the caret first to a position that doesn't
		// disappear.
		
		par.removeChild(table);
		editor.forceRedraw();
		editor.focusEditor();
		editor.updateToolbar();
		break;
		case "TO-table-copy":
		 var table = this.getClosest("table");
		 if(HTMLArea.is_ie)
		 {
		   
		   tablecopy = table.outerHTML;
		 }
		 else
		 {
		   tablecopy = editor.getOuterHTML();
		   tablecopynode = table.cloneNode(true);
		 }
		
		if (!table) {
			break;
		}
		
		break;
		case "TO-table-paste":
		editor.focusEditor();
		 if(HTMLArea.is_ie)
		 {
			if(typeof tablecopy != "undefined")
			{
			 var sel=editor._getSelection();
			 var range=editor._createRange(sel);
			 range.pasteHTML(tablecopy);
			}
			else
			{
				alert("Please first copy any table.")
			}
		 }
		 else
		 {
		 	if(typeof tablecopynode != "undefined")
			{
			 	var newtable = tablecopynode.cloneNode(true);
				editor.insertNodeAtSelection(newtable);
			}
			else
			{
				alert("Please first copy any table.")
			}
		 }
		 
		
		
		break;
		case "TO-clean_table":
		var table = this.getClosest("table");
		if (!table) {
			break;
		}
		cleanTable(table);
		editor.forceRedraw();
		editor.focusEditor();
		editor.updateToolbar();
		break;
		case "TO-join-tables":
		var table = this.getClosest("table");
		
		var nextTable = getNextTable(table);
		
		if((nextTable.tagName).toLowerCase() == "table")
		{
		  if((nextTable.rows[0]).cells.length == (table.rows[0]).cells.length)
		  {
			 for(var i=0;i<(nextTable.rows).length;i++)
			 {
				 var cloneTr = (nextTable.rows[i]).cloneNode(true);
				 var row = table.rows[((table.rows).length -1)];
				 row.parentNode.appendChild(cloneTr);
				 
			 }
			 
			var par = nextTable.parentNode;
			par.removeChild(nextTable);
			editor.forceRedraw();
			editor.focusEditor();
			editor.updateToolbar();
		  }
		}
		break;
		
		case "TO-split-tables":
		
		var table = this.getClosest("table");
		var tr = this.getClosest("tr");
		var rowIndex = tr.rowIndex;
		
		if(rowIndex > 0)
		{
			var tbody = this.getClosest("tbody");
			var cloneTbody = tbody.cloneNode(false);
			var cloneTable = table.cloneNode(false);
			var br =  document.createElement("br");
			
			cloneTable.appendChild(cloneTbody);
			for(var i=tr.rowIndex;i<table.rows.length;i++)
			{
				var tempRow = table.rows[i];
				var cloneRow = tempRow.cloneNode(true);
				cloneTbody.appendChild(cloneRow);
			}
			if(HTMLArea.is_ie)
			{
				
				table.insertAdjacentElement("afterEnd",br);
			
				br.insertAdjacentElement("afterEnd",cloneTable); 
			}
			else
			{
			   table.parentNode.insertBefore(br,table.nextSibling); 
				br.parentNode.insertBefore(cloneTable,br.nextSibling);
			}
			
			var maxrows=table.rows.length;
			for(var j=maxrows-1;j>=rowIndex;j-- )
			{
				table.deleteRow(j);
			}
		}
		break;
		
		// CELLS
	    case "TO-cell-split":
		var td = this.getClosest("td");
		if (!td) {
			break;
		}
		splitCell(td);
		break;
	    case "TO-cell-insert-before":
	    case "TO-cell-insert-after":
		var td = this.getClosest("td");
		if (!td) {
			break;
		}
		var tr = td.parentNode;
		var otd = td.cloneNode(true);
		otd.innerHTML = mozbr;
		
		tr.insertBefore(otd, /after/.test(button_id) ? td.nextSibling : td);
		editor.forceRedraw();
		editor.focusEditor();
		break;
	    case "TO-cell-delete":
		var td = this.getClosest("td");
		if (!td) {
			break;
		}
		if (td.parentNode.cells.length == 1) {
			alert(i18n["not-del-last-cell"]);
			break;
		}
		// set the caret first to a position that doesn't disappear
		selectNextNode(td);
		td.parentNode.removeChild(td);
		editor.forceRedraw();
		editor.updateToolbar();
		break;
	    case "TO-cell-merge":
		// !! FIXME: Mozilla specific !!
		var sel = editor._getSelection();
		var range, i = 0;
		var rows = [];
		var row = null;
		var cells = null;
		if (!HTMLArea.is_ie) {
			try {
				while (range = sel.getRangeAt(i++)) {
					var td = range.startContainer.childNodes[range.startOffset];
					if (td.parentNode != row) {
						row = td.parentNode;
						(cells) && rows.push(cells);
						cells = [];
					}
					cells.push(td);
				}
			} catch(e) {/* finished walking through selection */}
			rows.push(cells);
		} else {
			// Internet Explorer "browser"
			var td = this.getClosest("td");
			if (!td) {
				alert(i18n["Please click into some cell"]);
				break;
			}
			var tr = td.parentElement;
			var no_cols = prompt(i18n["How many columns would you like to merge?"], 2);
			if (!no_cols) {
				// cancelled
				break;
			}
			var no_rows = prompt(i18n["How many rows would you like to merge?"], 2);
			if (!no_rows) {
				// cancelled
				break;
			}
			var cell_index = td.cellIndex;
			while (no_rows-- > 0) {
				td = tr.cells[cell_index];
				cells = [td];
				for (var i = 1; i < no_cols; ++i) {
					td = td.nextSibling;
					if (!td) {
						break;
					}
					cells.push(td);
				}
				rows.push(cells);
				tr = tr.nextSibling;
				if (!tr) {
					break;
				}
			}
		}
		var HTML = "";
		for (i = 0; i < rows.length; ++i) {
			// i && (HTML += "<br />");
			var cells = rows[i];
			for (var j = 0; j < cells.length; ++j) {
				// j && (HTML += "&nbsp;");
				var cell = cells[j];
				HTML += cell.innerHTML;
				(i || j) && (cell.parentNode.removeChild(cell));
			}
		}
		var td = rows[0][0];
		td.innerHTML = HTML;
		td.rowSpan = rows.length;
		td.colSpan = rows[0].length;
		editor.selectNodeContents(td);
		editor.forceRedraw();
		editor.focusEditor();
		break;

		// PROPERTIES

	    case "TO-table-prop":
		this.dialogTableProperties();
		break;

	    case "TO-row-prop":
		var sel = editor._getSelection();
		var range, i = 0;
		var row = null;
		var cells = [];
		if (!HTMLArea.is_ie) 
		{
			try 
			{
				while (range = sel.getRangeAt(i++)) {
					var td = range.startContainer.childNodes[range.startOffset];
					if (td.parentNode != row) {
						if(td && (td.tagName).toLowerCase() == "td")
						{
							cells.push(td.parentNode);
							row=td.parentNode;
						}
					}
				}
			} catch(e) {/* finished walking through selection */}
		
		}
	
		this.dialogRowCellProperties(false,cells);
		break;

	    case "TO-cell-prop":
		var sel = editor._getSelection();
		var range, i = 0;
		var row = null;
		var cells = [];
		if (!HTMLArea.is_ie) 
		{
			try {
				while (range = sel.getRangeAt(i++)) {
					var td = range.startContainer.childNodes[range.startOffset];
					
					if(td && (td.tagName).toLowerCase() == "td")
						cells.push(td);
				}
			} catch(e) {/* finished walking through selection */}
			
		}
		this.dialogRowCellProperties(true,cells);
		break;
		case "TO-col-move-right":
		var td = this.getClosest("td");
	
		if(td)
		{
			var cellindex = td.cellIndex;
			var table = this.getClosest("table");

			if(table.tagName.toLowerCase() == "table")
			{
				
				var trs = table.getElementsByTagName("tr");
		
				for(j = 0; j < trs.length;++j)
				{
					
					var tr = trs[j];
					var tds = tr.getElementsByTagName("td");
					var firsttd = tds[cellindex];
					var secondtd = tds[cellindex+1];
					if(secondtd)
						tr.insertBefore(secondtd,firsttd);
				}
				if(secondtd)
					selectNextNode(secondtd);
			}
		}
		break;
		case "TO-col-move-left":
		var td = this.getClosest("td");
		if(td)
		{
			var cellindex = td.cellIndex;
			var table = this.getClosest("table");
			
			if(table.tagName.toLowerCase() == "table")
			{
				var trs = table.getElementsByTagName("tr");
				
				for(j = 0; j < trs.length;++j)
				{
					
					var tr = trs[j];
					var tds = tr.getElementsByTagName("td");
					var firsttd = tds[cellindex-1];
					var secondtd = tds[cellindex];
					if(firsttd)
						tr.insertBefore(secondtd,firsttd);
					
				}
				if(firsttd)
					selectPreviousNode(firsttd);
			}
		}
		
		break;
		case "TO-sort":
		
		var table = this.getClosest("table");
		var tr = this.getClosest("tr");
		var totalcols = (tr.getElementsByTagName("td")).length;
		var td = this.getClosest("td");
		var cellindex = td.cellIndex;
		this.dialogSortProperties(totalcols,cellindex,table);
		//sortTable(table,cellindex,false);
		
		break;
	    default:
		alert("Button [" + button_id + "] not yet implemented");
	}
};

// the list of buttons added by this plugin

TableOperations.btnList = [
	// table properties button
	["table-prop",       "table"],
	["table-delete",     "table"],
	["table-copy",     "table"],
	["table-paste",     "table"],
	["clean_table",      "table"],
	["sort",             "td"],
	["join-tables",      "table"],
	["split-tables",      "table"],
	
	null,			// separator

	// ROWS
	["row-prop",         "tr"],
	["row-insert-above", "tr"],
	["row-insert-under", "tr"],
	["row-copy-above",   "tr"],
	["row-copy-under",   "tr"],
	["row-delete",       "tr"],
	["row-split",        "td[rowSpan!=1]"],
	["move-row-up",      "tr"],
	["move-row-down",    "tr"],
	null,

	// COLS
	["col-insert-before", "td"],
	["col-insert-after",  "td"],
	["col-delete",        "td"],
	["col-split",         "td[colSpan!=1]"],
	["col-move-right",         "td"],
	["col-move-left",         "td"],
	null,

	// CELLS
	["cell-prop",          "td"],
	["cell-insert-before", "td"],
	["cell-insert-after",  "td"],
	["cell-delete",        "td"],
	["cell-merge",         "tr"],
	["cell-split",         "td[colSpan!=1,rowSpan!=1]"]
	];

	if(is_safari_2)
	{
	  TableOperations.btnList = [];
	}


//// GENERIC CODE [style of any element; this should be moved into a separate
//// file as it'll be very useful]
//// BEGIN GENERIC CODE -----------------------------------------------------

TableOperations.getLength = function(value) {
	var len = parseInt(value);
	if (isNaN(len)) {
		len = "";
	}
	return len;
};



// Returns an HTML element for a widget that allows color selection.  That is,
// a button that contains the given color, if any, and when pressed will popup
// the sooner-or-later-to-be-rewritten select_color.jsp dialog allowing user
// to select some color.  If a color is selected, an input field with the name
// "f_st_"+name will be updated with the color value in #123456 format.
TableOperations.createColorButton = function(doc, editor, color, name) {
	if (!color) {
		color = "";
	} else if (!/#/.test(color)) {
		color = HTMLArea._colorToRgb(color);
	}

	var df = doc.createElement("span");
 	var field = doc.createElement("input");
	field.type = "hidden";
	df.appendChild(field);
	var fName = "f_st_" + name;
 	field.name = fName;
 	field.id = fName;
	field.value = color;
	var button = doc.createElement("span");
	button.className = "buttonColor";
	df.appendChild(button);
	var span = doc.createElement("span");
	span.className = "chooser";
	// span.innerHTML = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
	span.style.backgroundColor = color;
	button.appendChild(span);
	button.onmouseover = function() { if (!this.disabled) { this.className += " buttonColor-hilite"; }};
	button.onmouseout = function() { if (!this.disabled) { this.className = "buttonColor"; }};
	span.onclick = function() {
		if (this.parentNode.disabled) {
			return false;
		}
		editor._popupDialog("select_color.jsp", function(color) {
			if (color) {
				span.style.backgroundColor = "#" + color;
				field.value = "#" + color;
			}
		}, ("EID:"+field.id),400,400);
	};
	var span2 = doc.createElement("span");
	span2.innerHTML = "&#x00d7;";
	span2.className = "nocolor";
	span2.title = TableOperations.I18N["Unset color"];
	button.appendChild(span2);
	span2.onmouseover = function() { if (!this.parentNode.disabled) { this.className += " nocolor-hilite"; }};
	span2.onmouseout = function() { if (!this.parentNode.disabled) { this.className = "nocolor"; }};
	span2.onclick = function() {
		span.style.backgroundColor = "";
		field.value = "";
	};
	return df;
};

TableOperations.createStyleLayoutFieldset = function(doc, editor, el) {
	var i18n = TableOperations.I18N;
	var fieldset = doc.createElement("fieldset");
	var legend = doc.createElement("legend");
	fieldset.appendChild(legend);
	legend.innerHTML = i18n["Layout"];
	var table = doc.createElement("table");
	fieldset.appendChild(table);
	table.style.width = "100%";
	var tbody = doc.createElement("tbody");
	table.appendChild(tbody);

	var tagname = el.tagName.toLowerCase();
	var tr, td, input, select, option, options, i;

	if (tagname != "td" && tagname != "tr" && tagname != "th") {
		tr = doc.createElement("tr");
		tbody.appendChild(tr);
		td = doc.createElement("td");
		td.className = "label";
		tr.appendChild(td);
		td.innerHTML = i18n["Alignment"] + ":";
		td = doc.createElement("td");
		tr.appendChild(td);
		select = doc.createElement("select");
		td.appendChild(select);
		select.name = "f_align";
		options = ["Baseline", "Right","Texttop","Absmiddle","Left","Absbottom","Bottom","Middle","Top"];
		for (i in options) {
			var Val = options[i];
			var val = options[i].toLowerCase();
			option = doc.createElement("option");
			option.innerHTML = i18n[Val];
			option.value = val;
			option.selected = (("" + el.align).toLowerCase() == val);
			select.appendChild(option);
		}
	}

	tr = doc.createElement("tr");
	tbody.appendChild(tr);
	td = doc.createElement("td");
	td.className = "label";
	tr.appendChild(td);
	td.innerHTML = i18n["Width"] + ":";
	td = doc.createElement("td");
	tr.appendChild(td);
	input = doc.createElement("input");
	input.type = "text";
	input.value = TableOperations.getLength(el.style.width);
	input.size = "5";
	input.name = "f_st_width";
	input.style.marginRight = "0.5em";
	td.appendChild(input);
	select = doc.createElement("select");
	select.name = "f_st_widthUnit";
	option = doc.createElement("option");
	option.innerHTML = i18n["percent"];
	option.value = "%";
	option.selected = /%/.test(el.style.width);
	select.appendChild(option);
	option = doc.createElement("option");
	option.innerHTML = i18n["pixels"];
	option.value = "px";
	option.selected = /px/.test(el.style.width);
	select.appendChild(option);
	option = doc.createElement("option");
	option.innerHTML = i18n["points"];
	option.value = "pt";
	option.selected = /pt/.test(el.style.width);
	select.appendChild(option);
	td.appendChild(select);

	select.style.marginRight = "0.5em";
	td.appendChild(doc.createTextNode(i18n["Text align"] + ":"));
	select = doc.createElement("select");
	select.style.marginLeft = select.style.marginRight = "0.5em";
	td.appendChild(select);
	select.name = "f_st_textAlign";
	options = ["Left", "Center", "Right", "Justify"];
	if (tagname == "td") {
		options.push("Char");
	}
	input = doc.createElement("input");
	input.name = "f_st_textAlignChar";
	input.size = "1";
	input.style.fontFamily = "monospace";
	td.appendChild(input);
	for (i in options) {
		var Val = options[i];
		var val = Val.toLowerCase();
		option = doc.createElement("option");
		option.value = val;
		option.innerHTML = i18n[Val];
		option.selected = (el.style.textAlign.toLowerCase() == val);
		select.appendChild(option);
	}
	function setCharVisibility(value) {
		input.style.visibility = value ? "visible" : "hidden";
		if (value) {
			input.focus();
			input.select();
		}
	};
	select.onchange = function() { setCharVisibility(this.value == "char"); };
	setCharVisibility(select.value == "char");

	tr = doc.createElement("tr");
	tbody.appendChild(tr);
	td = doc.createElement("td");
	td.className = "label";
	tr.appendChild(td);
	td.innerHTML = i18n["Height"] + ":";
	td = doc.createElement("td");
	tr.appendChild(td);
	input = doc.createElement("input");
	input.type = "text";
	input.value = TableOperations.getLength(el.style.height);
	input.size = "5";
	input.name = "f_st_height";
	input.style.marginRight = "0.5em";
	td.appendChild(input);
	select = doc.createElement("select");
	select.name = "f_st_heightUnit";
	option = doc.createElement("option");
	option.innerHTML = i18n["percent"];
	option.value = "%";
	option.selected = /%/.test(el.style.height);
	select.appendChild(option);
	option = doc.createElement("option");
	option.innerHTML = i18n["pixels"];
	option.value = "px";
	option.selected = /px/.test(el.style.height);
	select.appendChild(option);
	option = doc.createElement("option");
	option.innerHTML = i18n["points"];
	option.value = "pt";
	option.selected = /pt/.test(el.style.width);
	select.appendChild(option);
	td.appendChild(select);

	select.style.marginRight = "0.5em";
	td.appendChild(doc.createTextNode(i18n["Vertical align"] + ":"));
	select = doc.createElement("select");
	select.name = "f_st_verticalAlign";
	select.style.marginLeft = "0.5em";
	td.appendChild(select);
	options = ["Top", "Middle", "Bottom", "Baseline"];
	for (i in options) {
		var Val = options[i];
		var val = Val.toLowerCase();
		option = doc.createElement("option");
		option.value = val;
		option.innerHTML = i18n[Val];
		option.selected = (el.style.verticalAlign.toLowerCase() == val);
		select.appendChild(option);
	}

	return fieldset;
};

// Returns an HTML element containing the style attributes for the given
// element.  This can be easily embedded into any dialog; the functionality is
// also provided.
TableOperations.createStyleFieldset = function(doc, editor, el) {
	
	var i18n = TableOperations.I18N;
	var fieldset = doc.createElement("fieldset");
	var legend = doc.createElement("legend");
	fieldset.appendChild(legend);
	legend.innerHTML = i18n["CSS Style"];
	var table = doc.createElement("table");
	fieldset.appendChild(table);
	table.style.width = "100%";
	var tbody = doc.createElement("tbody");
	table.appendChild(tbody);

	var tr, td, input, select, option, options, i;

	tr = doc.createElement("tr");
	tbody.appendChild(tr);
	td = doc.createElement("td");
	tr.appendChild(td);
	td.className = "label";
	td.innerHTML = i18n["Background"] + ":";
	td = doc.createElement("td");
	tr.appendChild(td);
	var df = TableOperations.createColorButton(doc, editor, el.style.backgroundColor, "backgroundColor");
	df.firstChild.nextSibling.style.marginRight = "0.5em";
	td.appendChild(df);
	td.appendChild(doc.createTextNode(i18n["Image URL"] + ": "));
	input = doc.createElement("input");
	input.type = "text";
	input.name = "f_st_backgroundImage";
	if (el.style.backgroundImage.match(/url\(\s*(.*?)\s*\)/)) {
		input.value = RegExp.$1;
	}
	// input.style.width = "100%";
	td.appendChild(input);

	tr = doc.createElement("tr");
	tbody.appendChild(tr);
	td = doc.createElement("td");
	tr.appendChild(td);
	td.className = "label";
	td.innerHTML = i18n["FG Color"] + ":";
	td = doc.createElement("td");
	tr.appendChild(td);
	td.appendChild(TableOperations.createColorButton(doc, editor, el.style.color, "color"));

	// for better alignment we include an invisible field.
	input = doc.createElement("input");
	input.style.visibility = "hidden";
	input.type = "text";
	td.appendChild(input);
	if (el.tagName.toLowerCase() != "tr") {
		tr = doc.createElement("tr");
		tbody.appendChild(tr);
		td = doc.createElement("td");
		tr.appendChild(td);
		td.className = "label";
		td.innerHTML = i18n["Border"] + ":";
		td = doc.createElement("td");
		tr.appendChild(td);

		var colorButton = TableOperations.createColorButton(doc, editor, el.style.borderColor, "borderColor");
		var btn = colorButton.firstChild.nextSibling;
		td.appendChild(colorButton);
		// borderFields.push(btn);
		btn.style.marginRight = "0.5em";

		select = doc.createElement("select");
		var borderFields = [];
		td.appendChild(select);
		select.name = "f_st_borderStyle";
		options = ["none", "dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset"];
		var localizedOpts = [ TableOperations.I18N["border_none"], TableOperations.I18N["border_dotted"], 
													TableOperations.I18N["border_dashed"], TableOperations.I18N["border_solid"], 
													TableOperations.I18N["border_double"], TableOperations.I18N["border_groove"], 
													TableOperations.I18N["border_ridge"], TableOperations.I18N["border_inset"],
													TableOperations.I18N["border_outset"]]; 
		var currentBorderStyle = el.style.borderStyle;
		// Gecko reports "solid solid solid solid" for "border-style: solid".
		// That is, "top right bottom left" -- we only consider the first
		// value.
		(currentBorderStyle.match(/([^\s]*)\s/)) && (currentBorderStyle = RegExp.$1);
		for (i in options) {
			var val = options[i];
			option = doc.createElement("option");
			option.value = val;
			option.innerHTML = localizedOpts[i];
			(val == currentBorderStyle) && (option.selected = true);
			select.appendChild(option);
		}
		select.style.marginRight = "0.5em";
		function setBorderFieldsStatus(value) {
			for (i in borderFields) {
				var el = borderFields[i];
				el.style.visibility = value ? "hidden" : "visible";
				if (!value && (el.tagName.toLowerCase() == "input")) {
					el.focus();
					el.select();
				}
			}
		};
		select.onchange = function() { setBorderFieldsStatus(this.value == "none"); };

		input = doc.createElement("input");
		borderFields.push(input);
		input.type = "text";
		input.name = "f_st_borderWidth";
		input.value = TableOperations.getLength(el.style.borderWidth);
		if(input.value=="")
		{
			input.value="1";
		}
		input.size = "5";
		td.appendChild(input);
		input.style.marginRight = "0.5em";
		var span = doc.createElement("span");
		span.innerHTML = i18n["pixels"];
		td.appendChild(span);
		borderFields.push(span);

		setBorderFieldsStatus(select.value == "none");
	}
	if (el.tagName.toLowerCase() == "table") {
		// the border-collapse style is only for tables
		tr = doc.createElement("tr");
		tbody.appendChild(tr);
		td = doc.createElement("td");
		td.className = "label";
		tr.appendChild(td);
		input = doc.createElement("input");
		input.type = "checkbox";
		input.name = "f_st_borderCollapse";
		input.id = "f_st_borderCollapse";
		var val = (/collapse/i.test(el.style.borderCollapse));
		input.checked = val ? 1 : 0;
		td.appendChild(input);
		//input.checked = true;
		td = doc.createElement("td");
		tr.appendChild(td);
		var label = doc.createElement("label");
		label.htmlFor = "f_st_borderCollapse";
		label.innerHTML = i18n["Collapsed borders"];
		td.appendChild(label);
	   
				
	}
	if(el.tagName.toLowerCase() == "table" || el.tagName.toLowerCase() == "tr")
	{
		tr=doc.createElement("tr");
		tbody.appendChild(tr);
		td=doc.createElement("td");
		td.className="label";
		tr.appendChild(td);
		input=doc.createElement("input");
		input.type="checkbox";
		td.appendChild(input);
		input.name=input.id="f_our_globalStyle";
		td=doc.createElement("td");
		tr.appendChild(td);
		label=doc.createElement("label");
		label.htmlFor="f_our_globalStyle";
		label.innerHTML="Apply style to all cells";
		td.appendChild(label);
	}
	
	if(el.tagName.toLowerCase() == "table" || el.tagName.toLowerCase() == "tr" || el.tagName.toLowerCase() == "td")
	{
		
		//if(el.className != "" && el.className != "htmtableborders")
		{
			tr=doc.createElement("tr");
			tbody.appendChild(tr);
			td=doc.createElement("td");
			td.className="label";
			tr.appendChild(td);
			input=doc.createElement("input");
			input.type="checkbox";
			td.appendChild(input);
			input.name=input.id="f_overrideclass";
			td=doc.createElement("td");
			tr.appendChild(td);
			label=doc.createElement("label");
			label.htmlFor="f_overrideclass";
			label.innerHTML="Override class";
			td.appendChild(label);
		}
	}
	

	return fieldset;
};

TableOperations.style_mapping={f_st_backgroundColor:{s:"background-color",ie:"backgroundColor"},f_st_color:{s:"color",ie:"color"},f_st_backgroundImage:{s:"background-image",m:"url('%s')",ie:"backgroundImage"},f_st_borderStyle:{s:"border-style",c:/^border-?(right|top|left|bottom)?-?(width|color)$/i,ie:"borderStyle"},f_st_borderWidth:{s:"border-width",m:"%spx",c:/^border-?(right|top|left|bottom)?-?(style|color)$/i,ie:"borderWidth"},f_st_borderColor:{s:"border-color",c:/^border-?(right|top|left|bottom)?-?(style|width)$/i,ie:"borderColor"},f_st_borderCollapse:{s:"border-collapse",ie:"borderCollapse",m:{"true":"collapse","false":""}},f_st_width:{s:"width",ie:"width"},f_st_height:{s:"height",ie:"height"},f_st_textAlign:{s:"text-align",ie:"textAlign"},f_st_verticalAlign:{s:"vertical-align",ie:"verticalAlign"},f_st_margin:{s:"margin",ie:"margin"},f_st_padding:{s:"padding",ie:"padding"}};

TableOperations.style_ops=function(style,params)
{
	 var cleaned={};
	 for(var prop in params)
	 {
	  var val=params[prop];
	  var m=TableOperations.style_mapping[prop];
	  if(m)
	  {
	   if(val&&typeof m.m=="string")val=m.m.replace(/%s/g,val);
	   else if(typeof m.m=="object"&&typeof m.m[""+val]!="undefined")
	   val=m.m[""+val];
	   if(val===null||!/\S/.test(val))
	   {
		if(HTMLArea.is_ie)
		{
		 if(m.c)
		 {
		  for(var i in style)
		  if(m.c.test(i))
		  {
		   style.removeAttribute(i,false);
		   cleaned[i]=true;
		  }
		 }
		 style.removeAttribute(m.ie,false);
		cleaned[m.ie]=true;
	   }
	   else
	   {
		if(m.c)
		{
		 for(var i=style.length;--i>=0;)
		  if(m.c.test(style.item(i)))
		  {
		   style.removeProperty(i.nodeName);
		   cleaned[i.nodeName]=true;
		  }
		}
		style.removeProperty(m.s);cleaned[m.s]=true;
	   }
	   }
	   else 
	   try
	   {
		if(HTMLArea.is_ie)
		{
		 if(!cleaned[m.ie])style.setAttribute(m.ie,val,false);
		}
		else
		{
		 if(!cleaned[m.s])style.setProperty(m.s,val,"");
		}
	   }catch(e){};
	  }
	 }
   };

TableOperations.processStyle=function(params,element)
{
	var style=element.style,i;
	var classes=element.className;
	
	if(params.f_st_width)
		params.f_st_width=params.f_st_width+params.f_st_widthUnit;
	if(params.f_st_height)
		params.f_st_height=params.f_st_height+params.f_st_heightUnit;

	var changestyle = "true";
	if(element.className != "" && element.className != "htmtableborders")
	{
		if(params.f_overrideclass == false)
		{
			changestyle = "false";
		}
	}
	if(changestyle =="true")
	{
		TableOperations.style_ops(style,params);
	
		element.__msh_globalStyle=params.f_our_globalStyle;
		var tagname=element.tagName.toLowerCase();
		if(tagname=="table")
		{ 
			
		}
		if(params.f_our_globalStyle)
		{
			var tmpst=	{f_st_borderColor:params.f_st_borderColor,f_st_borderWidth:params.f_st_borderWidth,f_st_borderStyle:params.f_st_borderStyle,f_st_backgroundColor:params.f_st_backgroundColor,f_st_color:params.f_st_color,f_st_textAlign:params.f_st_textAlign,f_st_verticalAlign:params.f_st_verticalAlign,f_overrideclass:params.f_overrideclass};
			if(tagname=="tr")
			{
				tmpst.f_st_height=params.f_st_height;tmpst.f_st_heightUnit="";
			}
			var tds=element.getElementsByTagName("td");
			for(i=tds.length;--i>=0;)
				TableOperations.processStyle(tmpst,tds[i]);
		}
		if	(tagname=="td")
		{
			var tmpst={f_st_width:params.f_st_width,f_st_widthUnit:""};
			var table=element;
			while(table&&!/^table$/i.test(table.tagName))table=table.parentNode;
			if(table)
			{
				for(i=table.rows.length;--i>=0;)
					TableOperations.style_ops(table.rows[i].cells[element.cellIndex].style,tmpst);
			}
		}
	
		if	(tagname=="tr")
		{
			
			if(params.f_our_globalStyle)
			{
				var tmpst=	{f_st_borderColor:params.f_st_borderColor,f_st_borderWidth:params.f_st_borderWidth,f_st_borderStyle:params.f_st_borderStyle,f_st_backgroundColor:params.f_st_backgroundColor,f_st_color:params.f_st_color,f_st_textAlign:params.f_st_textAlign,f_st_verticalAlign:params.f_st_verticalAlign};
				var tds=element.getElementsByTagName("td");
				for(i=tds.length;--i>=0;)
					TableOperations.processStyle(tmpst,tds[i]);
			}
		}
	}
	
};


function sortTable(tblEl, col, rev,sortType,sortHeader) {
   var childs = tblEl.childNodes;
  // The first time this function is called for a given table, set up an
  // array of reverse sort flags.
  tblEl.reverseSort = new Array();
  tblEl.reverseSort[col] = rev;
  var tmpEl;
  var i, j;
  var minVal, minIdx;
  var testVal;
  var cmp;
  if(sortHeader == "0")
  {
	  i = 0;
  }
  else
  {
	  i = 1;
  }
  for (i; i < tblEl.rows.length - 1; i++) {

    // Assume the current row has the minimum value.
    minIdx = i;
    minVal = getTextValue(tblEl.rows[i].cells[col]);

    // Search the rows that follow the current one for a smaller value.
    for (j = i + 1; j < tblEl.rows.length; j++) {
      testVal = getTextValue(tblEl.rows[j].cells[col]);
      cmp = compareValues(minVal, testVal,sortType);
      
	  // Negate the comparison result if the reverse sort flag is set.
      if (tblEl.reverseSort[col])
        cmp = -cmp;
      // Sort by the second column (team name) if those values are equal.
      if (cmp == 0 && col != 1)
        cmp = compareValues(getTextValue(tblEl.rows[minIdx].cells[1]),
                            getTextValue(tblEl.rows[j].cells[1]),sortType);
      // If this row has a smaller value than the current minimum, remember its
      // position and update the current minimum value.
      if (cmp > 0) {
        minIdx = j;
        minVal = testVal;
      }
    }

    // By now, we have the row with the smallest value. Remove it from the
    // table and insert it before the current row.
    if (minIdx > i) 
	{
	  var parent = (tblEl.rows[minIdx]).parentNode;	
	  tmpEl = parent.removeChild(tblEl.rows[minIdx]);
	  parent.insertBefore(tmpEl, tblEl.rows[i]);
	}
  }

 
  return false;
}

//-----------------------------------------------------------------------------
// Functions to get and compare values during a sort.
//-----------------------------------------------------------------------------

// This code is necessary for browsers that don't reflect the DOM constants
// (like IE).
if (document.ELEMENT_NODE == null) {
  document.ELEMENT_NODE = 1;
  document.TEXT_NODE = 3;
}

function getTextValue(el) 
{
  var i;
  var s;
  // Find and concatenate the values of all text nodes contained within the
  // element.
  s = "";
  for (i = 0; i < el.childNodes.length; i++)
    if (el.childNodes[i].nodeType == document.TEXT_NODE)
      s += el.childNodes[i].nodeValue;
    else if (el.childNodes[i].nodeType == document.ELEMENT_NODE &&
             el.childNodes[i].tagName == "BR")
      s += " ";
    else
      // Use recursion to get text within sub-elements.
      s += getTextValue(el.childNodes[i]);

  return normalizeString(s);
}

function compareValues(v1, v2,sortType) {
  v1 = v1.toLowerCase();
  v2 = v2.toLowerCase();
  var f1, f2;

  // If the values are numeric, convert them to floats.
  if(sortType == "1")
  {
	  f1 = parseFloat(v1);
	  f2 = parseFloat(v2);
	  if (!isNaN(f1) && !isNaN(f2)) {
		v1 = f1;
		v2 = f2;
	  }
  }

  // Compare the two values.
  if (v1 == v2)
    return 0;
  if (v1 > v2)
    return 1
  return -1;
}

// Regular expressions for normalizing white space.
var whtSpEnds = new RegExp("^\\s*|\\s*$", "g");
var whtSpMult = new RegExp("\\s\\s+", "g");

function normalizeString(s) 
{
  s = s.replace(whtSpMult, " ");  // Collapse any multiple whites space.
  s = s.replace(whtSpEnds, "");   // Remove leading or trailing white space.
  return s;
}


// this function requires the file PopupDiv/PopupWin to be loaded from browser
TableOperations.prototype.dialogSortProperties = function(totalcols,cellindex,table) 
{
	
	var i18n = TableOperations.I18N;
	var dialog = new PopupWin(this.editor, i18n["Table Properties"], function(dialog, params) {
		var f_sort_column;
		var f_sort_type;
		var f_sort_order;
		var f_sort_header;
		for (var i in params) 
		{
			var val = params[i];
			switch (i) 
			{
			    case "f_sort_column":
				f_sort_column = val;
				break;
			    case "f_sort_type":
				f_sort_type = val;
				break;
			    case "f_sort_order":
				f_sort_order = val;
				break;
			    case "f_sort_header":
				f_sort_header = val;
				break;
			}
		}
		var rev = false;
		if(f_sort_order == "0")
		{
		   rev = false;
		}
		else
		{
		   rev = true;
		}
		sortTable(table,f_sort_column,rev,f_sort_type,f_sort_header)
		
		dialog.editor.forceRedraw();
		dialog.editor.focusEditor();
		dialog.editor.updateToolbar();
		
	},
	function (dialog) 
	{
		
		var strOption="";
		for(var i=0;i<totalcols;++i)
		{
		  var tmp = i+1;
		  if (i == cellindex)
		  {
			strOption=strOption+"<option value='"+i+"' selected>Column"+tmp+"</option>";
		  }
		  else
		  {
			  strOption=strOption+"<option value='"+i+"'>Column"+tmp+"</option>";
		  }

		  
		  
		}
		
		dialog.content.style.width = "400px";
		dialog.content.innerHTML = " \
		<div class='title'\>Sort Properties</div> \
		<table style='width:100%'> \
		  <tr> \
			<td> \
			  <fieldset><legend>Sort Options</legend> \
			   <table style='width:100%'> \
				<tr> \
				  <td class='label' width='30%'>Column:</td> \
				  <td class='value' width='70%'> \
			        <select name='f_sort_column'>"+strOption+"</select> \
			     </td> \
				</tr> \
			    <tr> \
				  <td class='label'>Order:</td> \
				  <td class='value'> \
			        <select name='f_sort_order'> \
                      <option value='0'>Ascending</option> \
                      <option value='1'>Descending</option> \
                    </select> \
			     </td> \
				</tr> \
			    <tr> \
				  <td class='label'>Type:</td> \
				   <td class='value'> \
			        <select name='f_sort_type'> \
                      <option value='0'>Text</option> \
                      <option value='1'>Number</option> \
                    </select> \
			     </td> \
				</tr> \
			   <tr> \
				  <td class='label'>My Table has:</td> \
				   <td class='value'> \
			        <select name='f_sort_header'> \
                      <option value='1'>Header row</option> \
                      <option value='0'>No header row</option> \
                    </select> \
			     </td> \
				</tr> \
			   </table> \
			  </fieldset> \
			</td> \
		  </tr> \
		 </table> \
		";

		dialog.modal = true;
		dialog.addButtons("ok", "cancel");
		dialog.showAtElement(dialog.editor._iframe, "c");
	},200,400 )
}

