GUI Components JavaScript DHTML






/****
    JsTable v0.4.5 (20050725) written by AT Mulyana (atmulyana@yahoo.com)
  This libary is to create DHTML widget of Table on web page which is
  editable, cell navigatable and its content is submittable to web server.
  The target browser for this widget are :
    - Netscape 7.1+ / Mozilla 1.4+ or other Gecko browser whose the same
      or the newer version of Gecko engine.
    - Internet Explorer 6+
    - Opera 7.5+
    I hope you get the best version so that this script can run correctly
  You should get the documentaion to see how to use this script
    
  Copyright (C) 2005 AT Mulyana (atmulyana@yahoo.com)
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License or (at your option) any later version.
    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.
    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Send the bug report to 'atmulyana@yahoo.com' (Tell the exact version of your
browser and under which Operating System you run the script)
Currently, this script is personal work of myself, not involving other people or
company including the company where I work.
*****/
/****** Checks the browser family ******/
function JsTableCheckBrowser()
{
  var navFamily = navigator.userAgent.toLowerCase();
  if (navFamily.indexOf('opera')!=-1) { 
    var ver = parseFloat( navFamily.substring(navFamily.indexOf('opera')+6,
      navFamily.length) );
    if (ver >= 7.5) navFamily = 'Opera7';
    else navFamily = '';
  } else if (navFamily.indexOf('msie')!=-1) {
    var ver = parseFloat( navFamily.substring(navFamily.indexOf('msie')+5,
      navFamily.length) );
    if (ver >= 6.0) navFamily = 'IE6';
    else navFamily = '';
  } else if (navFamily.indexOf('gecko')!=-1) {
    var ver = parseFloat( navFamily.substring(navFamily.indexOf('gecko')+6,
      navFamily.length) );
    if (ver >= 20030624) navFamily = 'Gecko'; //Good Gecko; Netscape 7.1+/Mozilla 1.4+
    else navFamily = '';
  } else {
    navFamily = '';
  }
  
  return navFamily;
}
var JsTableNavFamily = JsTableCheckBrowser();
/********** Adds additional useful methods to the standart objects **********/
String.prototype.strip = function() { //Removes leading and trailing white space(s)
   return this.toString().replace(/^\s+/,'').replace(/\s+$/,'');
};
String.prototype.isNumeric = function() { //Does the string evaluate to a numeric value?
  var re = /-?\s*\d*\.?\d+/;
  var val = this.toString();
  val = val.strip();
  var valid = true;
  var found = re.exec(val);
  if (!found) valid=false;
  else valid = (found[0].length==val.length);
  return valid;
};
//Can the string be used as variabel name?
String.prototype.isQualifiedVarName = function() {
  var re = /[a-zA-Z_]\w*/;
  var val = this.toString();
  var valid = true;
  var found = re.exec(val);
  if (!found) valid=false;
  else valid = (found[0].length==val.length);
  return valid;
};
//Does the string evaluate to a date value? (format: 'dd-mm-yyyy' or 'mm-dd-yyyy')
//If true then returns a normalized date value
String.prototype.isDate = function(sFormat) {
  var sFormat = (sFormat+'').toLowerCase();
   //Only 'd-m-y' or 'm-d-y' is accepted (It implies the paramater may
   //be omitted ==> 'd-m-y' will be used)
  if (sFormat!='m-d-y') sFormat = 'd-m-y';
  var idxDay = 0;
  var idxMonth = 1;
  if (sFormat=='m-d-y') {
    idxDay = 1;
    idxMonth = 0;
  }
  
  var sDate = this.toString().strip();
  var bValid = true;
  var arMonthlong = [0,31,28,31,30,31,30,31,31,30,31,30,31];
  var regDate = /(\d{1,2}\s*-\s*\d{1,2}\s*-\s*\d{4,4})/;
  
  var ar = regDate.exec(sDate);
  if (ar) {
    bValid = (sDate.length==ar[0].length);
    if (!bValid) return false;
  } else
    return false;
  
  sDate = sDate.replace(/\s+/g,''); //Removes all white spaces
  var arDate = sDate.split('-');
  var iYear = parseInt(arDate[2],10);
  var iMonth = parseInt(arDate[idxMonth],10);
  var iDay = parseInt(arDate[idxDay],10);
  bValid = (iMonth > 0) && (iMonth <= 12);
  if (bValid) {
    bValid = (iDay > 0);
    if (iMonth==2) {
      if (iYear%4) bValid = bValid && (iDay <= 28);
      else bValid = bValid && (iDay <= 29);
    } else {
      bValid = bValid && (iDay <= arMonthlong[iMonth]);
    }
  }
  
  if (bValid) {
    if (iDay < 10) iDay = '0' + iDay;
    if (iMonth < 10) iMonth = '0' + iMonth;
    iYear = '0000'.substring(0, 4 - (iYear+'').length) + iYear;
    if (sFormat=='m-d-y') return (iMonth+'-'+iDay+'-'+iYear);
    return (iDay+'-'+iMonth+'-'+iYear);
  }
  return bValid;
};
//Does the string evaluate to a date-time value? (format: 'dd-mm-yyyy hh:nn:ss'
//or 'mm-dd-yyyy hh:nn:ss')
//If true then returns a normalized date-time value
String.prototype.isDateTime = function(sFormat) {
  var sDt = this.toString().strip();
  var re = /((\d{1,2}\s*-\s*\d{1,2}\s*-\s*\d\d\d\d)\s+(\d{1,2}\s*:\s*\d{1,2}:\s*\d{1,2}))/;
  var ar = sDt.match(re);
  var bValid = true;
  if (ar) {
    bValid = (sDt.length==ar[0].length);
    if (!bValid) return bValid;
  } else
    return false;
  
  //Checks the date part
  var sDate = ar[2].isDate(sFormat);
  if (!sDate) return false;
  
  //Checks the time part
  ar[3] = ar[3].replace(/\s+/g,''); //Removes all white spaces
  var arTime = ar[3].split(':');
  var iHour = parseInt(arTime[0],10);
  var iMinute = parseInt(arTime[1],10);
  var iSecond = parseInt(arTime[2],10);
  bValid = (iHour >= 0) && (iHour < 24);
  if (bValid) bValid = (iMinute >= 0) && (iMinute < 60);
  if (bValid) bValid = (iSecond >= 0) && (iSecond < 60);
  
  if (bValid) {
    if (iHour < 10) iHour = '0' + iHour;
    if (iMinute < 10) iMinute = '0' + iMinute;
    if (iSecond < 10) iSecond = '0' + iSecond;
    return (sDate+' '+iHour+':'+iMinute+':'+iSecond);
  }
  return bValid;
};
//Gives denomination to the string if it evaluates to a numeric value
String.prototype.giveDenomination = function(denominator,fracDigits) {
  var pointDec;
  if (denominator!='.') { //Ignores denominator except ',' and '.'
    denominator = ',';
    var pointDec = '.';
  } else pointDec = ',';
  var sNumber = this.toString();
  if (!sNumber.isNumeric()) return sNumber;
  sNumber = sNumber.replace(/\s/g,'');
  var sSign = '';
  if (sNumber.charAt(0)=='-') {
    sSign = '-';
    sNumber = sNumber.substring(1,sNumber.length);
    if (parseFloat(sNumber)==0.0) sSign = '';
  }
  var sDec = '';
  var i = sNumber.indexOf('.');
  if (i!=-1) {
    sDec = sNumber.substring(i+1,sNumber.length); sDec = sDec.replace(/0+$/,'');
    sNumber = sNumber.substring(0,i);
    if (!sNumber) sNumber = '0';
  }
  if (fracDigits) {
    fracDigits = parseInt(fracDigits);
    fracDigits = (isNaN(fracDigits)? 0 : fracDigits);
    if (!sDec) sDec = '0';
    sDec = Math.round( parseFloat('0.'+sDec)* Math.pow(10,fracDigits) ) + '';
    while (sDec.length < fracDigits) sDec = '0' + sDec;
    if (sDec.length > fracDigits) {
      i = parseInt(sDec.substring(0,1));
      sDec = sDec.substring(1,sDec.length);
      sNumber = (parseInt(sNumber)+i) + '';
    }
  }
  var arNum = new Array();
  while (sNumber.length > 3) {
    arNum[arNum.length] = sNumber.substring(sNumber.length-3,sNumber.length);
    sNumber = sNumber.substring(0,sNumber.length-3);
  }
  if (sNumber.length > 0) arNum[arNum.length] = sNumber;
  arNum.reverse();
  if (sDec) sDec = pointDec + sDec;
  return (sSign+arNum.join(denominator)+sDec);
};
//Gives denomination to the string if it evaluates to a numeric value
String.prototype.removeDenomination = function(denominator,alterPointDecToPeriod,ignoreNumeric) {
  var pointDec = ',';
  if (denominator!='.') { //Ignores denominator except ',' and '.'
    denominator = ',';
    pointDec = '.';
  }
  var sNumber = this.toString();
  sNumber = sNumber.replace(new RegExp('\\'+denominator,'g'),'');
  var sNumber1 = sNumber.replace(new RegExp('\\'+pointDec,'g'),'.');
  if (sNumber1.isNumeric() || ignoreNumeric) {
    if (alterPointDecToPeriod) return sNumber1;
    else return sNumber;
  }
  return this.toString();
};
//To search if the 'elm' is inside the array;
//The 'elm' is not an object
Array.prototype.isThere = function(elm) {
  var s = this.join('|~&*&~|');
  return (s.indexOf(elm+'')!=-1);
};
//Returns the date value with format 'dd-mm-yyyy'
Date.prototype.ddmmyyyy = function() {
  day = this.getDate();
  month = this.getMonth()+1;
  year = this.getFullYear();
  if (day<10) day='0'+day;
  if (month<10) month='0'+month;
  return (day+'-'+month+'-'+year);
};
//Returns the date value with format 'mm-dd-yyyy'
Date.prototype.mmddyyyy = function() {
  day = this.getDate();
  month = this.getMonth()+1;
  year = this.getFullYear();
  if (day<10) day='0'+day;
  if (month<10) month='0'+month;
  return (month+'-'+day+'-'+year);
};
//Returns the date value with format 'yyyy-mm-dd'
Date.prototype.sqldate = function() {
  day = this.getDate();
  month = this.getMonth()+1;
  year = this.getFullYear();
  if (day<10) day='0'+day;
  if (month<10) month='0'+month;
  if (year<10) year='0'+year;
  return (year+'-'+month+'-'+day);
};
//Returns the time-stamp with format according to parameter 'format'
//Possible values (incasesensitive) for parameter format:
//  'd-m-y'    ==> 'dd-mm-yyyy hh:nn:ss'
//  'm-d-y'    ==> 'mm-dd-yyyy hh:nn:ss'
//  'sql'    ==> 'yyyy-mm-dd hh:nn:ss'
Date.prototype.timeStamp = function(format) {
  format = (format+'').toLowerCase();
   //Only 'd-m-y' or 'm-d-y' or 'sql' is accepted (It implies the paramater may
   //be omitted ==> 'd-m-y' will be used)
  if (format!='m-d-y' && format!='sql') format = 'd-m-y';
  
  hour = this.getHours();
  minute = this.getMinutes();
  second = this.getSeconds();
  if (hour<10) hour='0'+hour;
  if (minute<10) minute='0'+minute;
  if (second<10) second='0'+second;
  if (format=='m-d-y') return (this.mmddyyyy()+' '+hour+':'+minute+':'+second);
  if (format=='sql') return (this.sqldate()+' '+hour+':'+minute+':'+second);
  return (this.ddmmyyyy()+' '+hour+':'+minute+':'+second);
};
//Changes the date value according to parameter 'ddmmyyyy'
//'ddmmyyyy' is the date value with format 'dd-mm-yyyy'
Date.prototype.setFrom_ddmmyyyy = function(ddmmyyyy) {
  ddmmyyyy = ddmmyyyy+'';
  ddmmyyyy = ddmmyyyy.isDate();
  if (!ddmmyyyy) return;
  var dates = ddmmyyyy.split('-');
  this.setFullYear( parseInt(dates[2],10), parseInt(dates[1],10)-1, parseInt(dates[0],10) );
}
//Changes the date value according to parameter 'mmddyyyy'
//'mmddyyyy' is the date value with format 'mm-dd-yyyy'
Date.prototype.setFrom_mmddyyyy = function(mmddyyyy) {
  mmddyyyy = mmddyyyy+'';
  mmddyyyy = mmddyyyy.isDate('m-d-y');
  if (!mmddyyyy) return;
  var dates = mmddyyyy.split('-');
  this.setFullYear( parseInt(dates[2],10), parseInt(dates[0],10)-1, parseInt(dates[1],10) );
}
//Changes the date value according to parameter 'sqldate'
//'sqldate' is the date value with format 'yyyy-mm-dd'
Date.prototype.setFrom_sqldate = function(sqldate) {
  sqldate = sqldate+'';
  var dates = sqldate.split('-'); //No Checking
  this.setFullYear( parseInt(dates[0],10), parseInt(dates[1],10)-1, parseInt(dates[2],10) );
}
if (JsTableNavFamily) { /************ The browser fulfils the requirement ***************/
function JsTableRemoveAllText(oParent)
{
  var sText = '';
  var oChild, sNodeName;
  var idx = 0;
  while (idx < oParent.childNodes.length) {
    oChild = oParent.childNodes[idx];
    sNodeName = oChild.nodeName;
    if (sNodeName!='INPUT') oParent.removeChild(oChild);
    if (sNodeName=='#text') {
      sText += oChild.nodeValue;
    } else if (sNodeName=='BR') {
      sText += '\n';
    } else {
      idx++;
      continue;
    }
  }
  return sText;
}
/********** All about column models to set the colums behavior in the JsTable *******/
var JsTableCellEditorSelect = null;
function JsTableSetCellEditorSelect()
{
  if (!JsTableCellEditorSelect) return;
  JsTableCellEditorSelect.select();
  JsTableCellEditorSelect.readOnly = false;
  JsTableCellEditorSelect = null;
}
var JsTableColumnIndex = 0;
function JsTableColumnClass(columnName,inputName,width,align)
{
  this.columnName = columnName || String.fromCharCode(160);
  this.inputName = inputName || ('col'+JsTableColumnIndex);
  JsTableColumnIndex++;
  align = (align+'').toLowerCase();
  this.align = ( ('left|center|right'.indexOf(align)!=-1)? align : 'left');
  this.width = ( isNaN(parseInt(width))? 20 : parseInt(width) );
  
  this.getInputElm = function(oCell) {
    var arElms = oCell.getElementsByTagName('INPUT');
    for (var i=0; i      if (arElms[i].getAttribute('name') == this.inputName) return arElms[i];
    }
  };
  
  this.getCellEditor = function(oCell,oJsTable) {
    return null;
  };
  this.isValid = function(val,oJsTable) {
    return true;
  };
  this.fixedValue = function(val,oJsTable) {
    if (typeof val == 'undefined') return '';
    return val.toString();
  };
  this.getValue = function(oCell,oJsTable) {
    return this.getInputElm(oCell).value;
  };
  this._getShownValue = function(val,oJsTable) {
    return val;
  };
  this.getShownValue = function(oCell,oJsTable) {
    return this._getShownValue(this.getInputElm(oCell).value,oJsTable);
  };
  this.getShownValueOnEdit = function(oCell,oJsTable) {
    return this.getShownValue(oCell,oJsTable);
  };
  this._setShownValue = function(val,oCell,oJsTable) {
    JsTableRemoveAllText(oCell);
    var arText = (val+'').split('\n');
    var oText, oBR;
    for (var i=0; i      oText = document.createTextNode(arText[i]);
      oCell.appendChild(oText);
      if (i        oBR = document.createElement('BR');
        oCell.appendChild(oBR);
      }
    }
  };
  this.setValue = function(val,oCell,oJsTable,oCellEditor) {
    val = this.fixedValue(val,oJsTable);
    this.getInputElm(oCell).value = val;
    if (oCellEditor) oCellEditor.value = this.getShownValue(oCell,oJsTable);
    else this._setShownValue( this._getShownValue(val,oJsTable), oCell, oJsTable);
  };
  this._setCellEditorSelect = function(oCellEditor) {
    JsTableCellEditorSelect = oCellEditor;
    setTimeout('JsTableSetCellEditorSelect()',0);
  };
  this.setEditorOnEdit = function(oCellEditor,oCell,oJsTable) {
    var val = this.getShownValueOnEdit(oCell,oJsTable);
    oCellEditor.value = val;
    oCellEditor.readOnly = false;
    this._setCellEditorSelect(oCellEditor);
  };
  this.setEditorOnCommit = function(oCellEditor,oCell,oJsTable) {
    var val = oCellEditor.value;
    oCellEditor.readOnly = true;
    oCellEditor.select(); //IE6, to hide text cursor
    if (JsTableNavFamily=='IE6') oJsTable._onclickIE6 = [oJsTable.row, oJsTable.col];
    oCellEditor.value = ""; //clear highlight selected text if any
    if (!this.isValid(val,oJsTable)) {
      if (oJsTable.tableModel.oldValIfInvalid) val = this.getShownValue(oCell,oJsTable);
    }
    this.setValue(val,oCell,oJsTable,oCellEditor);
  };
  this.setEditorOnArrive = function(oCellEditor,oCell,oJsTable) {
    var sText = JsTableRemoveAllText(oCell);
    //var oSbl = (oCell.nextSibling ? oCell.nextSibling : oCell.previousSibling);
    if (JsTableNavFamily=='Opera7') {
      oCellEditor.style.height = (oCell.offsetHeight-2) + 'px';
    } else if (document.compatMode=='CSS1Compat') {
      oCellEditor.style.width = (oCell.offsetWidth-3) + 'px';
      oCellEditor.style.height = (oCell.offsetHeight-4) + 'px';
    } else {
      oCellEditor.style.width = oCell.offsetWidth + 'px';
      oCellEditor.style.height = (oCell.offsetHeight-2) + 'px';
    }
    oCell.style.padding = '0px';
    oCellEditor.value = sText;
    oCellEditor.style.textAlign = this.align;
    oCellEditor = oCell.appendChild(oCellEditor);
  };
  this.setEditorOnRearrive = function(oCellEditor,oCell,oJsTable) {
     //Invoked when the currently active cell is the same as before
  };
  this.setEditorOnLeave = function(oCellEditor,oCell,oJsTable) {
    oCell.removeChild(oCellEditor);
    oCell.style.padding = '';
    if (oCell.style.removeProperty) {
      oCell.style.removeProperty('padding');
      //oCell.style.removeProperty('height');
    } else {
      oCell.style.padding = '';
      //oCell.style.height = '';
    }
    this._setShownValue(this.getShownValue(oCell,oJsTable),oCell,oJsTable);
  };
  this.containsEditor = function(oCell,oCellEditor) {
    //It returns integer because some consideration (See method oJsTable.setFocus
    //and JsTableColumnBoolean.containsEditor)
    if (oCell.contains(oCellEditor)) return -1;
    return 0;
  };
  this.addCell = function(oRow,oJsTable,val,primaryKey) {
    val = this.fixedValue(val);
    var oCell = oRow.insertCell(oRow.cells.length);
    oCell.style.textAlign = this.align;
    var oInput = document.createElement("INPUT");
    oInput.type = 'hidden';
    oInput.setAttribute('name',this.inputName);
    oInput.setAttribute('id',this.inputName); //IE6
    oInput.value = val;
    oCell.appendChild(oInput);
    this._setShownValue( this._getShownValue(val,oJsTable), oCell,oJsTable);
    return oCell;
  };
}
function JsTableColumnString(columnName,inputName,width,align)
{
  this.base = JsTableColumnClass;
  this.base(columnName,inputName,width,align);
  
  this._addCell_ = this.addCell;
  this.addCell = function(oRow,oJsTable,val,primaryKey) {
    var oCell = this._addCell_(oRow,oJsTable,val,primaryKey);
    oCell.onkeypress = JsTableOnStringKeyPress;
    return oCell;
  }
}
function JsTableColumnNumber(columnName,inputName,width,align,denomination,fracDigits)
{
  this.base = JsTableColumnClass;
  align = align || 'right';
  this.base(columnName,inputName,width,align);
  this.denomination = (denomination?true:false);
  this.fracDigits = parseInt(fracDigits); if (isNaN(fracDigits)) fracDigits = 0;
  
  this.isValid = function (val,oJsTable) {
    val = (val+'').removeDenomination(oJsTable.tableModel.numberDenominator,true);
    return val.isNumeric();
  };
  this.fixedValue = function (val,oJsTable) {
    var denominator = oJsTable.tableModel.numberDenominator;
    if (typeof val != 'number') val = (val+'').removeDenomination(denominator,true,true);
    val = parseFloat(val+'');
    if (isNaN(val)) return 0;
    val = (val+'').giveDenomination(denominator,this.fracDigits);
    val = parseFloat(val.removeDenomination(denominator,true));
    return val;
  };
  this.getValue = function(oCell,oJsTable) {
    return parseFloat(this.getInputElm(oCell).value);
  };
  this._getShownValue = function(val,oJsTable) {
    val = val+'';
    var denominator = oJsTable.tableModel.numberDenominator;
    val = val.giveDenomination(denominator,this.fracDigits);
    if (this.denomination) return val;
    return val.replace(new RegExp('\\'+denominator,'g'),'');
  };
  this.getShownValueOnEdit = function(oCell,oJsTable) {
    var val = this.getInputElm(oCell).value;
    var denominator = oJsTable.tableModel.numberDenominator;
    var pointDec = ',';
    if (denominator==',') pointDec = '.';
    return val.replace(/\./,pointDec);
  };
  this.addCell = function(oRow,oJsTable,val,primaryKey) {
    val = this.fixedValue(val,oJsTable);
    var denominator = oJsTable.tableModel.numberDenominator;
    var shownVal = (val+'').giveDenomination(denominator,this.fracDigits);
    if (!this.denomination) shownVal = shownVal.removeDenomination(denominator,false,true);
    var oCell = oRow.insertCell(oRow.cells.length);
    oCell.style.textAlign = this.align;
    var oInput = document.createElement("INPUT");
    oInput.type = 'hidden';
    oInput.setAttribute('name',this.inputName);
    oInput.setAttribute('id',this.inputName); //IE6
    oInput.value = val;
    oCell.appendChild(oInput);
    oCell.appendChild(document.createTextNode(shownVal));
    oCell.style.whiteSpace = 'nowrap';
    oCell.onkeypress = JsTableOnNumberKeyPress;
    return oCell;
  };
}
function JsTableColumnBoolean(columnName,inputName,width,align)
{
  this.base = JsTableColumnClass;
  align = align || 'center';
  this.base(columnName,inputName,width,align);
  
  this.setPrimaryKey = function(oCell,primaryKey) {
    this.getInputElm(oCell).value = primaryKey+'';
  };
  this.getCellEditor = function(oCell,oJsTable) {
    return this.getInputElm(oCell);
  };
  this.isValid = function (val) {
    return true; //Always true as usual evaluation in JavaScript, all values of all types
          //can be evaluated as boolean
  };
  this.fixedValue = function (val) {
       if (val) return true;
    return false;
  };
  this.getValue = function(oCell,oJsTable) {
    return this.getInputElm(oCell).checked;
  };
  this.getShownValue = function(oCell,oJsTable) {
    return this.getInputElm(oCell).checked;
  };
  this._setShownValue = function(val,oCell,oJsTable) {
  };
  this.setValue = function(val,oCell,oJsTable,oCellEditor) {
    this.getInputElm(oCell).checked = this.fixedValue(val);
  };
  this.setEditorOnEdit = function(oCellEditor,oCell,oJsTable) {
    oCellEditor.checked = !oCellEditor.checked;
    oCell._checked = oCellEditor.checked;
    oJsTable.onEdit = false;
  };
  this.setEditorOnCommit = function(oCellEditor,oCell,oJsTable) {
  };
  this.setEditorOnArrive = function(oCellEditor,oCell,oJsTable) {
    oCell.className = 'cell-focus';
    if (oCell._onclick) //oCellEditor.checked = !oCellEditor.checked;
      oJsTable.setOnEdit(); //Also checks if the cell is editable, at once
  };
  this.setEditorOnRearrive = function(oCellEditor,oCell,oJsTable) {
    this.setEditorOnArrive(oCellEditor,oCell,oJsTable);
  };
  this.setEditorOnLeave = function(oCellEditor,oCell,oJsTable) {
    oCell.className = '';
  };
  this.containsEditor = function(oCell,oCellEditor) {
    return 1;
  };
  this.addCell = function(oRow,oJsTable,bChecked,val) {
    var oCell = oRow.insertCell(oRow.cells.length);
    oCell.style.textAlign = this.align;
    var oEditor = document.createElement("INPUT");
    oEditor.type = 'checkbox';
    oEditor.className = 'checkbox';
    oEditor.setAttribute('name',this.inputName);
    oEditor.setAttribute('id',this.inputName); //IE6
    oEditor.value = val+'';
    oEditor.checked = this.fixedValue(bChecked);
    oEditor.defaultChecked = oEditor.checked;
    oCell.appendChild(oEditor);
    oEditor.onblur = JsTableOnBlur;
    oEditor.onclick = JsTableOnCheckboxClick;
    oEditor.onkeydown = JsTableOnCheckboxKeyDown;
    oEditor.onkeypress = JsTableOnCheckboxKeyPress;
    return oCell;
  };
}
//This constructor is used to create object for option values in
//column whose type of JsTableColumnOptions
function JsTableOptionValues(arValuesSent,arValuesShown)
{
  if (!arValuesSent) arValuesSent = [];
  if (!arValuesShown) arValuesShown = [];
  for (var i=0; i    if (typeof arValuesShown[i] == 'undefined') arValuesShown[i] = arValuesSent[i];
    this[arValuesSent[i]] = arValuesShown[i];
  }
}
function JsTableColumnOptions(columnName,inputName,width,align,options)
{
  this.base = JsTableColumnClass;
  this.base(columnName,inputName,width,align);
  this.options = options || (new JsTableOptionValues());
  
  var o = document.createElement('SELECT');
  o.style.overflow = 'hidden';
  o.style.margin = '0px';
  o.style.padding = '0px';
  o.style.borderStyle = 'none';
  o.style.width = '100%';
  for (var optVal in this.options) {
    opt = document.createElement('OPTION');
    opt.style.margin = '0px';
    opt.appendChild(document.createTextNode(this.options[optVal]));
    opt.setAttribute('value',optVal);
    o.appendChild(opt);
    //o.add(opt,null);
  }
  this.cellEditor = o;
  this.cellEditor._selectedIndex = -1;
  this.cellEditor.onblur = JsTableOnBlur;
  //this.cellEditor.onkeydown = JsTableOnKeyDown;
  //this.cellEditor.onkeypress = JsTableOnKeyPress;
  this.cellEditor.onkeyup = function (e) {
    if (this._selectedIndex >= 0) {
      this.selectedIndex = this._selectedIndex;
      this._selectedIndex1 = this._selectedIndex;
      this._selectedIndex = -1;
    }
  }
  /*if (JsTableNavFamily=='Opera7') { //For Linux
    this.cellEditor.onkeypress = function (e) {
      if (this._selectedIndex < 0 || (typeof this._selectedIndex=='undefined')) {
        this._repeatedKeypress = true;;
      }
    }
    this.cellEditor.onchange = function (e) {
      if (this._repeatedKeypress) {
        this.selectedIndex = this._selectedIndex1;
        this._repeatedKeypress = false;
      }
    }
  }*/
  
  this.getCellEditor = function(oCell,oJsTable) {
    if ( oJsTable.tableModel.isCellEditable(oCell.parentNode.rowIndex,oCell.cellIndex) )
      return this.cellEditor;
    return oJsTable.cellEditor;
  };
  this.isValid = function (val) {
    return (typeof this.options[val] != 'undefined');
  };
  this.fixedValue = function (val) {
       if (typeof val != 'undefined')
      if (typeof this.options[val] != 'undefined') return val;
    for (var optVal in this.options) return optVal;//the first option
  };
  this._getShownValue = function(val,oJsTable) {
    return this.options[val];
  };
  this.setEditorOnEdit = function(oCellEditor,oCell,oJsTable) {
  };
  this.setEditorOnCommit = function(oCellEditor,oCell,oJsTable) {
  };
  this.setEditorOnArrive = function(oCellEditor,oCell,oJsTable) {
    oCell.style.padding = '0px';
    JsTableRemoveAllText(oCell);
    var val = this.getValue(oCell,oJsTable);
    if (oCellEditor.options) { //Combo box
      for (var i=0; i        if (oCellEditor.options[i].value==val) break;
      oCellEditor = oCell.appendChild(oCellEditor);
      oCellEditor.selectedIndex = i;
      if (oCell._keydown) oCellEditor._selectedIndex = i;
    } else { //Text box
      if (JsTableNavFamily=='Opera7') {
        oCellEditor.style.height = (oCell.offsetHeight-2) + 'px';
      } else if (document.compatMode=='CSS1Compat') {
        oCellEditor.style.width = (oCell.offsetWidth-3) + 'px';
        oCellEditor.style.height = (oCell.offsetHeight-4) + 'px';
      } else {
        oCellEditor.style.width = oCell.offsetWidth + 'px';
        oCellEditor.style.height = (oCell.offsetHeight-2) + 'px';
      }
      oCellEditor.value = this._getShownValue(val,oJsTable);
      oCellEditor.style.textAlign = 'left';
      oCell.appendChild(oCellEditor);
    }
  };
  this.setEditorOnRearrive = function(oCellEditor,oCell,oJsTable) {
    if (oCell._keydown) oCellEditor._selectedIndex = oCellEditor.selectedIndex;
  };
  this.setEditorOnLeave = function(oCellEditor,oCell,oJsTable) {
    if (oCell.style.removeProperty) {
      oCell.style.removeProperty('padding');
    } else {
      oCell.style.padding = '';
    }
    if (oCellEditor._selectedIndex >= 0) {
      oCellEditor.selectedIndex = oCellEditor._selectedIndex;
      oCellEditor._selectedIndex = -1;
    }
    var val = oCellEditor.value;
    if (!oCellEditor.options) val = this.getInputElm(oCell).value; //Text box
    oCell.removeChild(oCellEditor);
    this.getInputElm(oCell).value = val;
    this._setShownValue( this._getShownValue(val,oJsTable), oCell,oJsTable);
  };
}
function JsTableColumnDate(columnName,inputName,width,align,saveAsSQLformat)
{
  this.base = JsTableColumnClass;
  align = align || 'center';
  this.base(columnName,inputName,width,align);
  this.saveAsSQLformat = (saveAsSQLformat?true:false);
  
  this.isValid = function (val,oJsTable) {
    val = val+'';
    return val.isDate(oJsTable.tableModel.dateFormat);
  };
  this.fixedValue = function (val,oJsTable) {
       var valid = this.isValid(val,oJsTable);
    if (valid) return valid;
    return '00-00-0000';
  };
  this.getValue = function(oCell,oJsTable) {
    return this.getShownValue(oCell,oJsTable);
  };
  this._getShownDate = function(val,dateFormat) {
    if (this.saveAsSQLformat) {
      if (val=='0000-00-00') return '00-00-0000';
      var dt = new Date();
      dt.setFrom_sqldate(val);
      if (dateFormat=='m-d-y') return dt.mmddyyyy();
      return dt.ddmmyyyy();
    }
    return val;
  };
  this.getShownValue = function(oCell,oJsTable) {
    var val = this.getInputElm(oCell).value;
    return this._getShownDate(val,oJsTable.tableModel.dateFormat);
  };
  this._getSavedDate = function(val,dateFormat) {
    if (this.saveAsSQLformat) {
      dt = new Date();
      if (val=='00-00-0000') return '0000-00-00';
      else if (dateFormat=='m-d-y') dt.setFrom_mmddyyyy(val);
      else dt.setFrom_ddmmyyyy(val);
      return dt.sqldate();
    }
    return val;
  };
  this.setValue = function(val,oCell,oJsTable,oCellEditor) {
    val = this.fixedValue(val,oJsTable);
    this.getInputElm(oCell).value = this._getSavedDate(val, oJsTable.tableModel.dateFormat);
    if (oCellEditor) oCellEditor.value = this.getShownValue(oCell,oJsTable);
    else this._setShownValue(val,oCell,oJsTable);
  };
  this.addCell = function(oRow,oJsTable,val) {
    val = this.fixedValue(val,oJsTable);
    var savedval = this._getSavedDate(val,oJsTable.tableModel.dateFormat);;
    var oCell = oRow.insertCell(oRow.cells.length);
    oCell.style.textAlign = this.align;
    var oInput = document.createElement("INPUT");
    oInput.type = 'hidden';
    oInput.setAttribute('name',this.inputName);
    oInput.setAttribute('id',this.inputName); //IE6
    oInput.value = savedval;
    oCell.appendChild(oInput);
    oCell.appendChild(document.createTextNode(val));
    oCell.style.whiteSpace = 'nowrap';
    oCell.onkeypress = JsTableOnNumberKeyPress;
    oCell.dateCol = true;
    return oCell;
  };
}
function JsTableColumnDateTime(columnName,inputName,width,align,saveAsSQLformat)
{
  this.base = JsTableColumnDate;
  this.base(columnName,inputName,width,align,saveAsSQLformat);
  
  this.isValid = function (val,oJsTable) {
    val = val+'';
    return val.isDateTime(oJsTable.tableModel.dateFormat);
  }
  this.fixedValue = function (val,oJsTable) {
       var valid = this.isValid(val,oJsTable);
    if (valid) return valid;
    return '00-00-0000 00:00:00';
  }
  this.getShownValue = function(oCell,oJsTable) {
    var val = this.getInputElm(oCell).value;
    var dt = val.split(/\s+/);
    var showndate = this._getShownDate(dt[0],oJsTable.tableModel.dateFormat);
    return (showndate+' '+dt[1]);
  };
  this.setValue = function(val,oCell,oJsTable,oCellEditor) {
    val = this.fixedValue(val,oJsTable);
    var dt = val.split(/\s+/);
    var saveddate = this._getSavedDate(dt[0],oJsTable.tableModel.dateFormat);
    this.getInputElm(oCell).value = saveddate + ' ' + dt[1];
    if (oCellEditor) oCellEditor.value = this.getShownValue(oCell,oJsTable);
    else this._setShownValue(val,oCell,oJsTable);
  };
  this.addCell = function(oRow,oJsTable,val) {
    val = this.fixedValue(val,oJsTable);
    var dt = val.split(/\s+/);
    var saveddate = this._getSavedDate(dt[0],oJsTable.tableModel.dateFormat);;
    var oCell = oRow.insertCell(oRow.cells.length);
    oCell.style.textAlign = this.align;
    var oInput = document.createElement("INPUT");
    oInput.type = 'hidden';
    oInput.setAttribute('name',this.inputName);
    oInput.setAttribute('id',this.inputName); //IE6
    oInput.value = saveddate + ' ' + dt[1];
    oCell.appendChild(oInput);
    oCell.appendChild(document.createTextNode(val));
    oCell.style.whiteSpace = 'nowrap';
    oCell.onkeypress = JsTableOnNumberKeyPress;
    oCell.datetimeCol = true;
    return oCell;
  };
}
function JsTableColumnLink(columnName,inputName,width,align,identifier,href)
{
  this.base = JsTableColumnClass;
  align = align || 'center';
  this.base(columnName,inputName,width,align);
  this.identifier = identifier;
  this.href = href+'';
  
  this.setPrimaryKey = function(oCell,primaryKey) {
    var oLink = this.getInputElm(oCell);
    var sHref = oLink.getAttribute("orgHref");
    sHref = sHref.replace(/__ROW__/g, oCell.parentNode.rowIndex);
    oLink.href = sHref.replace(/__PRIMARY_KEY__/g, primaryKey);
    oLink.setAttribute('primaryKey',primaryKey);
  };
  this.setRowIndex = function(oCell) {
    var oLink = this.getInputElm(oCell);
    var sHref = oLink.getAttribute("orgHref");
    sHref = sHref.replace(/__ROW__/g, oCell.parentNode.rowIndex);
    oLink.href = sHref.replace(/__PRIMARY_KEY__/g, oLink.getAttribute('primaryKey'));
  };
  this.getInputElm = function(oCell) {
    var arElms = oCell.getElementsByTagName('A');
    for (var i=0; i      if (arElms[i].getAttribute('name') == this.inputName) return arElms[i];
    }
  };
  this.getCellEditor = function(oCell,oJsTable) {
    return this.getInputElm(oCell);
  };
  this.getValue = function(oCell,oJsTable) {
    return this.getInputElm(oCell).href;
  };
  this.getShownValue = function(oCell,oJsTable) {
    return this.getInputElm(oCell).firstChild;
  };
  this.getShownValueOnEdit = function(oCell,oJsTable) {
  };
  this._setShownValue = function(val,oCell,oJsTable) {
    if (typeof val != 'object') val = document.createTextNode(val+'');
    var oLink = this.getInputElm(oCell);
    if (oLink.firstChild) oLink.replaceChild(val,oLink.firstChild);
    else oLink.appendChild(val);
  };
  this.setIdentifier = function(identifier,oCell,oJsTable) {
    this._setShownValue(identifier,oCell,oJsTable);
    this.identifier = identifier;
  };
  this.setValue = function(sHref,oCell,oJsTable,oCellEditor) {
    var oLink = this.getInputElm(oCell);
    oLink.href = sHref.replace(/__PRIMARY_KEY__/g,primaryKey);
    oLink.setAttribute('orgHref',sHref);
  };
  this.setEditorOnEdit = function(oCellEditor,oCell,oJsTable) {
    oJsTable.onEdit = false;
  };
  this.setEditorOnCommit = function(oCellEditor,oCell,oJsTable) {
  };
  this.setEditorOnArrive = function(oCellEditor,oCell,oJsTable) {
    oCell.className = 'cell-focus';
  };
  this.setEditorOnRearrive = function(oCellEditor,oCell,oJsTable) {
    this.setEditorOnArrive(oCellEditor,oCell,oJsTable);
  };
  this.setEditorOnLeave = function(oCellEditor,oCell,oJsTable) {
    oCell.className = '';
  };
  this.containsEditor = function(oCell,oCellEditor) {
    return 1;
  };
  this.addCell = function(oRow,oJsTable,sHref,primaryKey,iRow) {
    var oCell = oRow.insertCell(oRow.cells.length);
    oCell.style.textAlign = this.align;
    var oLink = document.createElement("A");
    oLink.setAttribute('name',this.inputName);
    if (!sHref) sHref = this.href;
    sHref = sHref + '';
    oLink.setAttribute('orgHref',sHref);
    oLink.setAttribute('primaryKey',primaryKey);
    sHref = sHref.replace(/__PRIMARY_KEY__/g,primaryKey);
    if (typeof oRow.rowIndex != 'undefined') iRow = oRow.rowIndex; //undefined for Opera7
    oLink.href = sHref.replace(/__ROW__/g,iRow);
    oCell.appendChild(oLink);
    var identifier = this.identifier;
    if (typeof this.identifier == 'object') {
      if (this.identifier.cloneNode) identifier = this.identifier.cloneNode(true);
      else identifier = this.identifier.toString();
    }
    this._setShownValue(identifier,oCell,oJsTable);
    if (JsTableNavFamily=='Opera7') {
      oLink.onclick = JsTableOnLinkClickOpera7;
      oLink.onmouseup = JsTableOnLinkMouseUpOpera7;
      //oLink.onkeypress = JsTableOnLinkKeyPress;
      oLink.onkeydown = JsTableOnLinkKeyDownOpera7;
    }
    oLink.onblur = JsTableOnBlur;
    return oCell;
  };
}
/***** Sets needed CSS *********************************/
function JsTableSetCSS()
{
  var noJsTableStyle = true;
  var o, hasMethodInsert = true;
  if (document.styleSheets) {
    if (!document.styleSheets.length) {
      o = document.getElementsByTagName('HEAD');
      if (o) {
        o = o[0];
        o.appendChild(document.createElement('STYLE'));
      }
    }
    var cssRules = 'cssRules';
    if (JsTableNavFamily=='IE6') cssRules = 'rules';
    var selectorText;
    for (i=0; i      o = document.styleSheets[i][cssRules];
      for (j=0; j        selectorText = o[j].selectorText.toLowerCase();
        if (selectorText=='.jstable' || selectorText=='table.jstable') {
          noJsTableStyle = false;
          break;
        }
      }
      if (!noJsTableStyle) break;
    }
    if (!document.styleSheets.length) hasMethodInsert = false; //We cannot insert new rules via DOM method
  } else {//if (document.styleSheets)
    hasMethodInsert = false;
  }
  
  var addRule = function(selector,sRule,o,iPhase) {
  }
  if (noJsTableStyle && hasMethodInsert) {
    o = document.styleSheets[0];
    if (JsTableNavFamily=='IE6') {
      addRule = function(selector,sRule,oStyle,iPhase) {
        oStyle.addRule(selector,sRule);
      }
    } else {
      addRule = function(selector,sRule,oStyle,iPhase) {
        oStyle.insertRule(selector + '{' + sRule + '}', o.cssRules.length);
      }
    }
  } else if (noJsTableStyle && !hasMethodInsert) {
    o = null;
      addRule = function(selector,sRule,oStyle,iPhase) {
        if (iPhase==1) document.write('<'+'style>\n');
        document.write(selector + '{' + sRule + '}\n');
        if (iPhase==2) document.write('<'+'/style>\n');
      }
  }
  var sCellStyle = 'font-family:arial,sans-serif; font-size:12px; ';
  var sCellEditorStyle = 'background-color:#cccccc; margin:0px; padding:0px; ' + sCellStyle;
  sCellStyle = 'background-color:white; height:18px; ' + sCellStyle;
  addRule('.JsTable', 'background-color:black', o, 1);
  addRule('.JsTable TH', sCellStyle, o, 0);
  addRule('.JsTable TD', sCellStyle, o, 0);
  addRule('.JsTable TEXTAREA', sCellEditorStyle, o, 0);
  addRule('.JsTable INPUT', sCellEditorStyle, o, 0);
  addRule('.JsTable INPUT.checkbox', 'background-color:transparent', o, 0);
  addRule('.JsTable .cell-focus', 'background-color:#cccccc', o, 0);
  addRule('.JsTable SELECT', 'height:16px; ' + sCellEditorStyle, o, 2);
}
JsTableSetCSS();
var JsTableGetKeyCode = function(e) {};
if (JsTableNavFamily=='Gecko') {
//Makes the event object in Gecko like the one in IE
  function JsTableGeckoEventButton() {
    switch (this.which) {
      case 1: return 1;
      case 2: return 4;
      case 3: return 2;
    }
  }
  function JsTableGeckoEventSrcElement() {
    return this.target;
  }
  function JsTableGeckoEventFromElement() {
    return this.relatedTarget;
  }
  function JsTableGeckoEventToElement() {
    return this.relatedTarget;
  }
  function JsTableGeckoEventReturnValue(bVal) {
    if (!bVal) this.preventDefault();
  }
  function JsTableGeckoEventCancelBubble(bVal) {
    if (bVal) this.stopPropagation();
  }
  function JsTableGeckoEventOffsetX() {
    return this.layerX;
  }
  function JsTableGeckoEventOffsetY() {
    return this.layerY;
  }
  //Other than Gecko, which doesn't support getter and setter statement, will not fail here
  eval("Event.prototype.button getter= JsTableGeckoEventButton");
  eval("Event.prototype.srcElement getter= JsTableGeckoEventSrcElement");
  eval("Event.prototype.fromElement getter= JsTableGeckoEventFromElement");
  eval("Event.prototype.toElement getter= JsTableGeckoEventToElement");
  eval("Event.prototype.returnValue setter= JsTableGeckoEventReturnValue");
  eval("Event.prototype.cancelBubble setter= JsTableGeckoEventCancelBubble");
  eval("Event.prototype.offsetX getter= JsTableGeckoEventOffsetX");
  eval("Event.prototype.offsetY getter= JsTableGeckoEventOffsetY");
  
//Emulates method contains in IE
  Element.prototype.contains = function(oNode) {
    while (oNode) {
      if (this == oNode) return true;
      oNode = oNode.parentNode;
    }
    return false;
  }
  JsTableGetKeyCode = function(e) {
    if (e.type=='keypress') {
      if (e.charCode) return e.charCode;
      else switch (e.keyCode) {
        case 8:  //Backspace
        case 9:  //Tab
        case 13: //Enter
          return e.keyCode;
        default:
          return e.keyCode*1000; //Multiply by 1000 to avoid overlapping with printable keyCode 
      }
    }
    return e.keyCode;
  };
} else if (JsTableNavFamily=='Opera7') {
  //Opera7 has different value for middle button from IE has, but we forgive it
  /*Event.prototype.button getter= function() {
    switch (this.button) {
      case 1: return 1;
      case 2: return 2;
      case 3: return 4;
    }
  }*/
  
  JsTableKeyCodeOnKeyDown = 0;
  JsTableGetKeyCode = function(e) {
    //Opera 7.1 has different keyCode for extended keys (thousands value)
    if (e.type=='keypress') {
      switch (e.keyCode) {
        case 113: if (JsTableKeyCodeOnKeyDown==81) return 81; // q
        case 57346:
          return 113000; //F2
        case 37:
        case 57387:
          return 37000;  //Left Arrow
        case 38:
        case 57385:
          return 38000;  //Up Arrow
        case 39: //Right arrow or single quote ( ' ) on Opera 7.2+
        case 57388:
          if (JsTableKeyCodeOnKeyDown==222) return 39; //single quote ( ' )
          return 39000;  //Right Arrow
        case 40:
        case 57386: return 40000;  //Down Arrow
        case 57395: return 46000;  //Delete
        case 57381: return 36000;  //Home
        case 57382: return 35000;  //End
        default   : return e.keyCode;
      }
    } else {
      JsTableKeyCodeOnKeyDown = e.keyCode;
      switch (e.keyCode) {
        case 57346: return 113; //F2
        case 57387: return 37;  //Left Arrow
        case 57385: return 38;  //Up Arrow
        case 57388: return 39;  //Right Arrow
        case 57386: return 40;  //Down Arrow
        case 57395: return 46;  //Delete
        case 57381: return 36;  //Home
        case 57382: return 35;  //End
        default   : return e.keyCode;
      }
    }
  };
} else { //IE 6
  JsTableGetKeyCode = function(e) {
    return e.keyCode;
  };
}
/************** Event Handler ********************/
function JsTableGetObjectsOnEvent(sTagName,e)
{
  if (!e) e = window.event;
  var oTarget = e.srcElement;
  var objs = {target: oTarget};
  while (sTagName.indexOf('|'+oTarget.nodeName+'|')==-1) {
    if (oTarget.nodeName=='TABLE') return null;
    if (oTarget.nodeName=='HTML') return null;
    oTarget = oTarget.parentNode;
    if (!oTarget) return null;
  }
  if (oTarget.nodeName=='TD' || oTarget.nodeName=='TH') {
    objs.cellEditor = null;
    objs.cell = oTarget;
  } else {
    objs.cellEditor = oTarget;
    objs.cell = oTarget.parentNode;
  }
  if (!objs.cell) return null;
  objs.row = objs.cell.parentNode;
  if (!objs.row) return null;
  objs.tbl = (objs.row.parentNode ? objs.row.parentNode.parentNode : null);
  if (!objs.tbl) return null;
  objs.jsTable = window['_'+objs.tbl.id];
  objs.event = e;
  objs.keyCode = JsTableGetKeyCode(e);
  return objs;
}
var JsTableColToResize = -1;
var JsTableOffsetXstartToResize = -1;
var JsTableObjectTblOnResize = null;
function JsTableHeaderOnMouseMove(e)
{
  if (!e) e = window.event;
  var oTarget = e.srcElement;
  var oTbl = oTarget;
  while (oTbl.nodeName!='TABLE') {
    oTbl = oTbl.parentNode;
    if (!oTbl) return;
  }
  var oRow = oTbl.rows[0];
  var bOnEdge = false;
  if (oTarget.tagName=='TH') {
    if (e.offsetX==0 && oTarget.cellIndex!=0) {
      JsTableColToResize = oTarget.cellIndex - 1; //Resize the left side column
      bOnEdge = true;
    }
    if (e.offsetX==oTarget.offsetWidth-1) {
      JsTableColToResize = oTarget.cellIndex; //Resize the left side column
      bOnEdge = true;
    }
  }
  
  if (bOnEdge) {
    oTbl.style.cursor = 'w-resize';
  } else {
    oTbl.style.cursor = 'default';
    JsTableColToResize = -1;
  }
}
function JsTableHeaderOnMouseOver(e)
{
  if (!e) e = window.event;
  var oTbl = e.srcElement;
  if (oTbl.tagName!='TABLE') return;
  if (!e.fromElement) return;
  if (e.fromElement.tagName!='TH') return;
  var oRow = oTbl.rows[0];
  var bOnEdge = (e.offsetY < oRow.offsetHeight && e.offsetX > 1); //On the edge precisely
  if (bOnEdge) {
    var iLeft = oRow.cells[0].offsetWidth + 1 + oRow.cells[1].offsetWidth;
    var iCol = 1;
    while (e.offsetX > iLeft) {
      iCol++;
      if (iCol==oRow.cells.length) break;
      iLeft += oRow.cells[iCol].offsetWidth + 1;
    }
    JsTableColToResize = iCol - 1; //Resize the left side column
    oTbl.style.cursor = 'w-resize';
  } else {
    oTbl.style.cursor = 'default';
    JsTableColToResize = -1;
  }
}
function JsTableHeaderOnMouseOut(e)
{
  if (!e) e = window.event;
  var oTarget = e.toElement;
  var oTbl = oTarget;
  while (oTbl) {
    if (oTbl.nodeName=='TABLE') break;
    oTbl = oTbl.parentNode;
  }
  if (!oTbl) {
    JsTableColToResize = -1;
    if (this.style) this.style.cursor = 'default';
  }
}
function JsTableStopDragOnResize(oJsTable,bHasFocus)
{
  oTbl = oJsTable.table;
  oTbl.style.cursor = 'default';
  oTbl.onmousemove = JsTableHeaderOnMouseMove;
  oTbl.onmouseover = JsTableHeaderOnMouseOver;
  oTbl.onmouseout = JsTableHeaderOnMouseOut;
  oTbl.onmouseup = null;
  if (document.releaseCapture) document.releaseCapture();
  else {
    document.removeEventListener('mouseup',JsTableOnResizeOnMouseUp,true);
    document.removeEventListener('mouseout',JsTableOnResizeOnMouseOut,true);
  }
  JsTableColToResize = -1;
  JsTableOffsetXstartToResize = -1;
  JsTableObjectTblOnResize = null;
  if (bHasFocus) oJsTable.setFocus(true);
}
function JsTableOnResizeOnMouseUp(e)
{
  if (!JsTableObjectTblOnResize) return;
  if (!e) e = window.event;
  var dx = e.screenX - JsTableOffsetXstartToResize;
  var oJsTable = window['_'+JsTableObjectTblOnResize.id];
  var bHasFocus = oJsTable.hasFocus;
  if (bHasFocus) oJsTable.setFocus(false);
  var oCol = oJsTable.tableModel.columns[JsTableColToResize];
  oCol.width += dx;
  if (oCol.width < 20) oCol.width = 20;
  var oTbl = oJsTable.table;
  for (var i=0; i    oTbl.rows[i].cells[JsTableColToResize].style.width = oCol.width + 'px';
    oTbl.rows[i].cells[JsTableColToResize].width = oCol.width;
  }
  JsTableStopDragOnResize(oJsTable,bHasFocus);
}
function JsTableOnResizeOnMouseOut(e)
{
  if (!JsTableObjectTblOnResize) return;
  if (!e) e = window.event;
  if (!e.toElement) {
    var oJsTable = window['_'+JsTableObjectTblOnResize.id];
    var bHasFocus = oJsTable.hasFocus;
    JsTableStopDragOnResize(oJsTable,bHasFocus);
  }
}
function JsTableOnMouseDown(e)
{
  if (JsTableColToResize >= 0) {
    if (!e) e = window.event;
    JsTableOffsetXstartToResize = e.screenX;
    JsTableObjectTblOnResize = this;
    this.onmousemove = null;
    this.onmouseover = null;
    this.onmouseout = null;
    if (JsTableNavFamily=='IE6') {
      this.setCapture();
      this.onmouseup = JsTableOnResizeOnMouseUp;
      this.onmouseout = JsTableOnResizeOnMouseOut;
    } else {
      document.addEventListener('mouseup',JsTableOnResizeOnMouseUp,true);
      document.addEventListener('mouseout',JsTableOnResizeOnMouseOut,true);
    }
  }
  var o = JsTableGetObjectsOnEvent('|TD|TH|',e);
  if (!o) return;
  var iRow = o.row.rowIndex;
  var iCol = o.cell.cellIndex;
  if (iRow < 1) {
    if (o.tbl.rows.length <= 1) return;
    iRow = 1;
  }
  if ('|TEXTAREA|INPUT|SELECT|A|'.indexOf('|'+o.target.nodeName+'|')!=-1) o.cellEditor = o.target;
  o.cell._onclick = true;
  if (JsTableNavFamily=='IE6' && o.jsTable.hasFocus && o.jsTable.row==iRow && o.jsTable.col==iCol) {
    if (o.target!=o.cellEditor) o.jsTable._onclickIE6 = [-1,-1];
    else if (o.target.nodeName=='TEXTAREA' ||
      (o.target.nodeName=='INPUT' && o.target.type=='text')) o.jsTable._onclickIE6 = [iRow,iCol];
  }
  o.jsTable.setActiveCell(iRow,iCol);
  if (o.cellEditor!=o.target) {
    o.event.returnValue = false;
    return false;
  }
}
function JsTableOnDblClick(e)
{
  var o = JsTableGetObjectsOnEvent('|TEXTAREA|INPUT|',e);
  if (!o) return;
  o.jsTable.setOnEdit();
}
function JsTableOnBlur(e)
{
  var o = JsTableGetObjectsOnEvent('|TEXTAREA|INPUT|SELECT|A|',e);
  if (!o) return;
  if (o.jsTable._onclickIE6)
    o.jsTable._onclickIE6 = (o.jsTable._onclickIE6[0]!=o.row.rowIndex
      || o.jsTable._onclickIE6[1]!=o.cell.cellIndex);
  if (o.jsTable._onmove) o.jsTable._onmove = false;
  else if (o.jsTable._onclickIE6) //IE 6
    //When JsTable has focus and then the active cell is clicked but not on the CellEditor,
    //such as checkbox or link, the blur event will occur but we want the JsTable still has focus
    o.cellEditor.focus();
  else if (o.jsTable.row==o.row.rowIndex && o.jsTable.col==o.cell.cellIndex)//used especially for Opera 7
    //must be the active cell which experiences the blur event. The event can happen on the previous
    //active cell whose different cell editor from the one owned the current active cell.
    //o.jsTable._onmove is useful when the cell editor remains the same
    { o.jsTable._onblur=true; o.jsTable.setFocus(false); }
  
  o.jsTable._onclickIE6 = false;
}
function JsTableOnKeyPress(e)
{
  var o = JsTableGetObjectsOnEvent('|TEXTAREA|INPUT|SELECT|',e);
  if (!o) return;
  var bRetVal = true;
  switch (o.keyCode) {
    case 37000: //Left Arrow
    case 38000: //Up Arrow
    case 39000: //Right Arrow
    case 40000: //Down Arrow
      if (o.jsTable.onEdit) break;
    case 13: //Enter
      if (o.cellEditor.nodeName=='A') break;
    case 113000: //F2
    case 27: //Esc
      o.event.returnValue = false;
      o.event.cancelBubble = true;
      bRetVal = false;
    default:
      
  }
  
  if (typeof o.jsTable.onkeypress == 'function') o.jsTable.onkeypress(o.event);
  if (!bRetVal) return false;
}
function JsTableGetNewCoordOnArrow(iArrowKey,iRow,iCol,oTbl,oRow)
{
  switch (iArrowKey) {
    case 37: //Left
    case 37000:
      return {row: iRow, col: ( (iCol>0)?(iCol-1):iCol )};
    case 38: //Up
    case 38000:
      return {row: ( (iRow>1)?(iRow-1):iRow ), col: iCol};
    case 39: //Right
    case 39000:
      return {row: iRow, col: ( (iCol    case 40: //Down
    case 40000:
      return {row: ( (iRow  }
}
function JsTableOnKeyDown(e)
{
  var o = JsTableGetObjectsOnEvent('|TEXTAREA|INPUT|SELECT|A|',e);
  if (!o) return;
  var iRow = o.row.rowIndex;
  var iCol = o.cell.cellIndex;
  var bRetVal = true;
  //Arrow keys
  if (o.keyCode >= 37 && o.keyCode <= 40) {
    if (!o.jsTable.onEdit) {
      var oCoord = JsTableGetNewCoordOnArrow(o.keyCode,iRow,iCol,o.tbl,o.row);
      o.cell._keydown = true;
      o.jsTable.setActiveCell(oCoord.row, oCoord.col);
      bRetVal = false;
    }
  } else {
    switch (o.keyCode) {
    case 13: //Enter
      if (o.cellEditor.nodeName=='A') break;
      if (!o.jsTable.onEdit) o.jsTable.setOnEdit();
      else {
        o.jsTable.setOnCommit();
        var keyCode = 0;
        if (o.jsTable.tableModel.enterAfterEdit == JsTable.ENTER_MOVE_DOWN) keyCode = 40;
        if (o.jsTable.tableModel.enterAfterEdit == JsTable.ENTER_MOVE_RIGHT) keyCode = 39;
        if (keyCode) {
          var oCoord = JsTableGetNewCoordOnArrow(keyCode,iRow,iCol,o.tbl,o.row);
          o.cell._keydown = true;
          o.jsTable.setActiveCell(oCoord.row, oCoord.col);
        }
      }
      bRetVal = false; break;
    case 113: //F2
      o.jsTable.setOnEdit();
      bRetVal = false; break;
    case 27: // Escape
      o.jsTable.setOnCommit();
      bRetVal = false; break;
    }
  }
  
  if (typeof o.jsTable.onkeydown == 'function') o.jsTable.onkeydown(o.event);
  if (!bRetVal) {
    o.event.returnValue = false;
    o.event.cancelBubble = true;
    return false;
  }
}
function JsTableOnCheckboxClick(e)
{
  var o = JsTableGetObjectsOnEvent('|INPUT|',e);
  if (!o) return;
  o.event.returnValue = false;
  o.cellEditor.checked = o.cell._checked;
}
function JsTableOnCheckboxKeyDown(e)
{
  var o = JsTableGetObjectsOnEvent('|INPUT|',e);
  if (!o) return;
  switch (o.keyCode) {
    case 32: //Space
      o.jsTable.setOnEdit();
    case 113: //F2
    case 27: // Escape
      o.event.returnValue = false;
      o.event.cancelBubble = true;
      return false;
    case 13: //Enter
      o.jsTable.setOnEdit();
      o.jsTable.onEdit = true;
  }
}
function JsTableOnCheckboxKeyPress(e)
{
  var o = JsTableGetObjectsOnEvent('|INPUT|',e);
  if (!o) return;
  if (o.keyCode==32) { //space
    o.event.returnValue = false;
    o.event.cancelBubble = true;
    return false;
  }
}
function JsTableOnStringKeyPress(e) {
  var o = JsTableGetObjectsOnEvent('|TEXTAREA|INPUT|',e);
  if (!o) return;
  if (!o.jsTable.onEdit && (o.keyCode >= 32 && o.keyCode <= 126)) { //typeable character
    o.cellEditor.readOnly = false;
    o.cellEditor.select(); //IE6
    o.jsTable.onEdit = true;
    o.cellEditor.value = '';//String.fromCharCode(o.keyCode);
  }
}
function JsTableOnNumberKeyPress(e)
{
  var o = JsTableGetObjectsOnEvent('|TEXTAREA|INPUT|',e);
  if (!o) return;
  
  var keyCode = o.keyCode;
  var val = o.cellEditor.value;
  var bTrueChar = ((keyCode >= 48 && keyCode <= 57)   //numeric keys
    || keyCode == 45);   //hyphen (-)
  var bDecOk = true;
  if (o.cell.dateCol || o.cell.datetimeCol) {
    //if (keyCode==45) return;//hyphen
    if (o.cell.datetimeCol)
      bTrueChar = bTrueChar || keyCode==32 || keyCode==58; //space, : (colon)
  } else {
    var pointDec = ',';
    if (o.jsTable.tableModel.numberDenominator==',') pointDec = '.';
    if (pointDec==',' && keyCode==44) {
      bTrueChar = true;
      bDecOk = (val.indexOf(',')==-1);//ok if decimal point not yet exist
    } else if (pointDec=='.' && keyCode==46) {
      bTrueChar = true;
      bDecOk = (val.indexOf('.')==-1);//ok if decimal point not yet exist
    }
    //if (keyCode==45 && val.indexOf('-')!=0) return; //hyphen
  }
  if (!o.jsTable.onEdit) {
    if (bTrueChar) {
      o.cellEditor.readOnly = false;
      o.cellEditor.select(); //IE6
      o.jsTable.onEdit = true;
      o.cellEditor.value = '';//String.fromCharCode(keyCode);
      return;
    }
  } else if ((bTrueChar && bDecOk)
  //  || keyCode == 13 || keyCode == 27  //Enter, Escape
    || keyCode == 46000 || keyCode == 8 || keyCode == 9 //Delete, Backspace, Tab
    || (keyCode >= 37000 && keyCode <= 40000)   //Arrow
    || keyCode == 0   //Some extended keys on Opera
    || keyCode == 36000 || keyCode == 35000  //Home, end
  ) {
    return;
  }
  o.event.returnValue = false;
  o.event.cancelBubble = true;
  return false;
}
function JsTableOnLinkClickOpera7(e)

  if (this._nocancelclick) this._nocancelclick = false;
  else return false;
}
var JsTableOnLinkMouseUpJsTableObject = null;
var JsTableOnLinkMouseUpLinkObject = null;
function JsTableOnLinkMouseUpOpera7(e) {
  var o = JsTableGetObjectsOnEvent('|A|',e);
  if (!o) return;
  JsTableOnLinkMouseUpLinkObject = o.cellEditor;
  JsTableOnLinkMouseUpJsTableObject = o.jsTable;
  setTimeout(
  'if (JsTableOnLinkMouseUpJsTableObject) { '
    + 'JsTableOnLinkMouseUpJsTableObject.setFocus(true); '
    + 'JsTableOnLinkMouseUpJsTableObject=null; } '
  + 'if (JsTableOnLinkMouseUpLinkObject) { '
    + 'JsTableOnLinkMouseUpLinkObject._nocancelclick=true; '
    + 'JsTableOnLinkMouseUpLinkObject.click(); '
    + 'JsTableOnLinkMouseUpLinkObject=null; }',0);
}
function JsTableOnLinkKeyDownOpera7(e)
{
  if (!e) e = window.event;
  if (e.keyCode==13) this._nocancelclick = true;
}
/************ End: Event Handler ****************************/
function JsTableModel(columns,phpStyle,numberDenominator,dateFormat,oldValIfInvalid,
  withPrimaryKey)
{
  //columns is a collection of instance of JsTableColumnClass
  if (typeof columns != 'object') columns = [];
  else if (!columns.length) columns = [];
  this.columns = columns;
  
  //Only ',' or '.' accepted
  if (numberDenominator != ',') numberDenominator = '.';
  this.numberDenominator = numberDenominator;
  
  //Only 'd-m-y' or 'm-d-y' accepted
  dateFormat = (dateFormat+'').toLowerCase();
  if (dateFormat != 'm-d-y') dateFormat = 'd-m-y';
  this.dateFormat = dateFormat;
  
  if (oldValIfInvalid) this.oldValIfInvalid = true;
  else this.oldValIfInvalid = false;
  
  if (phpStyle) {
    for (var i=0;i  }
  
  this.withPrimaryKey = (withPrimaryKey ? true : false);
  this.enterAfterEdit = JsTable.ENTER_STAY;
  
  this.isCellEditable = function(iRow,iCol) {
    return true;
  };
}
function JsTable(sId,oTableModel,oParent,oNextSibling)
{
  function errorId() {
    alert('The table Id is invalid or has been existed');
    return null;
  }
  if (typeof sId != 'string' || !sId) return errorId();
  if (!sId.isQualifiedVarName()) return errorId();
  if ( (typeof window[sId]!='undefined') || (typeof window['_'+sId]!='undefined')
    || document.getElementById(sId)) return errorId();
  
  if (!oParent && !oParent.insertBefore) {
    if (document.forms.length) {
      oParent = document.forms[document.forms.length];
    } else {
      oParent = document.body.appendChild(document.createElement('FORM'));
    }
  }
  
  var oTbl = document.createElement('TABLE');
  //oTbl.onmousemove = JsTableHeaderOnMouseMove;
  oTbl.id = sId;
  oTbl.className = 'JsTable';
  oTbl.cellSpacing = 1;
  oTbl.cellPadding = 0;
  
  /* Creates Column Headers */
  var o = oTbl.createTHead();
  o = o.insertRow(0);
  var columns = oTableModel.columns;
  var oText, oCell;
  for (var i=0; i    oText = document.createTextNode(columns[i].columnName);
    oCell = o.appendChild(document.createElement('TH'));
    oCell.style.width = columns[i].width + "px";
    oCell.appendChild(oText);
  }
  if (JsTableNavFamily == 'IE6') { //if (JsTableNavFamily != 'Gecko')
    oTbl.onmousemove = JsTableHeaderOnMouseMove;
    oTbl.onmouseover = JsTableHeaderOnMouseOver;
    oTbl.onmouseout = JsTableHeaderOnMouseOut;
  }
  
  if (!oNextSibling) oNextSibling = null;
  oTbl = oParent.insertBefore(oTbl,oNextSibling);
  window[sId] = oTbl;
  window['_'+sId] = this;
  this.table = oTbl;
  this.id = sId;
  this.tableModel = oTableModel;
  
  if (true) { //(JsTableNavFamily=='Opera7') {
    o = document.createElement('INPUT');
    o.type = 'text';
  } else {
    o = document.createElement('TEXTAREA');
    if (JsTableNavFamily=='IE6') o.style.overflow = 'hidden';
    else o.style.overflow = 'auto';
  }
  o.readOnly = true;
  o.style.width = '100%';
  o.style.height = '100%';
  o.style.margin = '0px';
  o.style.borderStyle = 'solid';
  o.style.borderWidth = '1px';
  //o.style.padding = '1px 1px 1px 0px';
  o.style.paddingRight = '1px';
  o.style.borderColor = '#cccccc';
  this.cellEditor = o;
  
  this.row = -1;
  this.col = -1;
  this.onEdit = false;
  this.hasFocus = false;
  
  oTbl.onmousedown = JsTableOnMouseDown;
  oTbl.onkeydown = JsTableOnKeyDown;
  oTbl.onkeypress = JsTableOnKeyPress;
  //oTbl.onblur = JsTableOnBlur;
  this.cellEditor.ondblclick = JsTableOnDblClick;
  //this.cellEditor.onkeydown = JsTableOnKeyDown;
  //this.cellEditor.onkeypress = JsTableOnKeyPress;
  this.cellEditor.onblur = JsTableOnBlur;
  
  this.onkeydown = function(e) {};
  this.onkeypress = function(e) {};
  this.oncellchange = function() {};
  this.oncommit = function() {};
  
  this._keys = [];
}
JsTable.prototype.getObjectsOnCell = function(iRow,iCol) {
  var oColumn = this.tableModel.columns[iCol];
  var oCell = this.table.rows[iRow];
  if (oCell) oCell = oCell.cells[iCol];
  var oCellEditor = oColumn.getCellEditor(oCell,this);
  if (!oCellEditor) oCellEditor = this.cellEditor;
  return {column: oColumn, cellEditor: oCellEditor, cell: oCell};
};
JsTable.prototype.getColumn = function(iCol) {
  return this.tableModel.columns[iCol];
};
JsTable.prototype.setHeader = function(sHeader, iCol) {
  var oCell = this.table.rows[0].cells[iCol];
  if (!oCell) return;
  JsTableRemoveAllText(oCell);
  oCell.appendChild(document.createTextNode(sHeader+""));
};
JsTable.prototype.setValue = function(val, iRow, iCol) {
  if (iRow < 1 || iCol < 0) return;
  var o = this.getObjectsOnCell(iRow,iCol);
  if (!o.cell) return;
  var oCellEditor = null;
  if (o.cellEditor) if (o.cell.contains(o.cellEditor)) oCellEditor = o.cellEditor;
  o.column.setValue(val,o.cell,this,oCellEditor);
};
JsTable.prototype.getValue = function(iRow, iCol) {
  var oTbl = this.table;
  if (iRow < 1) return;
  var oRow = oTbl.rows[iRow];
  if (!oRow) return;
  var oCell = oRow.cells[iCol];
  if (!oCell) return;
  var oColumn = this.tableModel.columns[iCol];
  oColumn.getValue(oCell,this);
};
//arguments list the values for each cell
JsTable.prototype.insertRow = function(args,primaryKey,iRow) {
  var oTbl = this.table;
  var arColumn = this.tableModel.columns;
  
  if (!iRow) iRow = oTbl.rows.length;
  iRow = parseInt(iRow);
  if (isNaN(iRow)) return;
  if (iRow > oTbl.rows.length || iRow < 1) iRow = oTbl.rows.length;
  if (!this.tableModel.withPrimaryKey) primaryKey = iRow;
  
  var arColKey = [];
  var i, j = 0;
  var oRow = oTbl.insertRow(iRow);
  for (i=0; i    arColumn[i].addCell(oRow, this, args[i], primaryKey, iRow);
    oRow.cells[i].style.width = arColumn[i].width + 'px';
    if (arColumn[i].setPrimaryKey) {
      arColKey[j] = i;
      j++;
    }
  }
  
  if (!this.tableModel.withPrimaryKey) {
    for (var i=iRow+1; i      for (j=0; j        var oCell = oTbl.rows[i].cells[arColKey[j]];
        arColumn[arColKey[j]].setPrimaryKey(oCell,i);
      }
    }
  }
  
  var oInput, oCell = oRow.cells[0];
  //The new row must have all keys
  for (i=0; i    oInput = document.createElement('INPUT');
    oInput.type = 'hidden';
    oInput.setAttribute('name',this._keys[i]);
    oCell.appendChild(oInput);
  }
};
JsTable.prototype.addMatrix = function(args2,primaryKeys) {
  for (var i=0; i    this.insertRow(args2[i],primaryKeys[i]);
  }
};
JsTable.prototype.deleteRow = function(iRow) {
  var oTbl = this.table;
  iRow = parseInt(iRow);
  if (isNaN(iRow)) return;
  if (iRow < 1 || iRow >= oTbl.rows.length) return;
  var bHasFocus = this.hasFocus;
  if (iRow == this.row && bHasFocus) this.setFocus(false);
  oTbl.deleteRow(iRow);
  var arColumn = this.tableModel.columns;
  if (!this.tableModel.withPrimaryKey) {
    for (var j=0; j      if (typeof arColumn[j].setPrimaryKey!='function') continue;
      for (var i=iRow; i        var oCell = oTbl.rows[i].cells[j];
        arColumn[j].setPrimaryKey(oCell,i);
      }
    }
  }
  for (var j=0; j    if (typeof arColumn[j].setRowIndex!='function') continue;
    for (var i=iRow; i      var oCell = oTbl.rows[i].cells[j];
      arColumn[j].setRowIndex(oCell);
    }
  }
  
  if (iRow >= oTbl.rows.length) iRow = oTbl.rows.length-1;
  if (iRow > 0) this.setActiveCell(iRow,this.col);
  else this.row = -1;
};
JsTable.prototype.insertKey = function(sKeyName,val,iRow) {
  var arColumn = this.tableModel.columns;
  for (var i=0; i    if (arColumn[i].inputName==sKeyName) {
      alert('JsTable.insertKey : this key name has been owned by the input of a column');
      return;
    }
  var oTbl = this.table;
  if (!iRow) iRow = 1;
  iRow = parseInt(iRow);
  if (isNaN(iRow)) return;
  if (iRow < 1 || iRow >= oTbl.rows.length) return;
  
  var iLength = 0;
  if ((typeof val != 'object') || (typeof val.length != 'number')) {
    val = [val];
    iLength = 1;
  } else 
    iLength = val.length;
  if (iRow+iLength > oTbl.rows.length) iLength = oTbl.rows.length - iRow;
  
  var oCell = oTbl.rows[iRow].cells[0];
  var bKeyExist = false;
  var arInputs = oCell.getElementsByTagName('INPUT');
  for (var i=0; i    if (arInputs[i].getAttribute('name')==sKeyName) {
      bKeyExist = true;
      break;
    }
  if (bKeyExist) {
    for (var i=0; i      oCell = oTbl.rows[iRow+i].cells[0];
      arInputs = oCell.getElementsByTagName('INPUT');
      for (var j=0; j        if (arInputs[j].getAttribute('name')==sKeyName) {
          arInputs[j].value = val[i];
          break;
        }
    }
  } else {
    var j = iRow + iLength;
    //All rows must have this key
    for (var i=0; i      oCell = oTbl.rows[i].cells[0];
      var oInput = document.createElement('INPUT');
      oInput.type = 'hidden';
      oInput.setAttribute('name',sKeyName);
      if (i >= iRow && i < j) oInput.value = val[i-iRow];
      oCell.appendChild(oInput);
    }
  }
};
JsTable.prototype.setActiveCell = function(iRow, iCol) {
  if (iRow < 1 || iRow >= this.table.rows.length
     || iCol < 0 || iCol >= this.tableModel.columns.length) return;
  if (!this.hasFocus) {
    this._oncellchange = (iRow != this.row || iCol != this.col);
    this.row = iRow;
    this.col = iCol;
    this.setFocus(true);
    return;
  }
  
  var o = this.getObjectsOnCell(iRow,iCol);
  if (this.row == iRow && this.col == iCol) {
    o.column.setEditorOnRearrive(o.cellEditor,o.cell,this);
    o.cell._onclick = false;
    o.cell._keydown = false;
    return;
  } else {
    if (this.row > 0 && this.col >= 0) {
      var oldCell = this.getObjectsOnCell(this.row,this.col);
      o.cell._keydown = oldCell.cell._keydown;
      oldCell.cell._keydown = false;
      //oldCell.cellEditor.blur();
      this._onmove = true;
      this.setFocus(false);
    }
  }
  
  this._oncellchange = true;
  this.row = iRow;
  this.col = iCol;
  this.setFocus(true);
};
  
JsTable.prototype.setOnEdit = function() {
  if (!this.tableModel.isCellEditable(this.row,this.col)) return;
  if (this.onEdit) return;
  if (this.row < 1 || this.col < 0) return;
  var o = this.getObjectsOnCell(this.row,this.col);
  this.onEdit = true;
  o.column.setEditorOnEdit(o.cellEditor,o.cell,this);
  //Enter cannot be canceled on Opera
  //if (o.cellEditor.value) o.cellEditor.value = o.cellEditor.value.replace(/\n/g,'').replace(/\r/g,'');
};
JsTable.prototype.setOnCommit = function() {
  if (!this.onEdit) return;
  if (this.row < 1 || this.col < 0) return;
  var o = this.getObjectsOnCell(this.row,this.col);
  this.onEdit = false;
  //Enter cannot be canceled on Opera
  //if (o.cellEditor.value) o.cellEditor.value = o.cellEditor.value.replace(/\n/g,'').replace(/\r/g,'');
  o.column.setEditorOnCommit(o.cellEditor,o.cell,this);
  this.oncommit();
};
JsTableActiveCellEditor = null;
JsTableSetCellEditorFocus = function() {
  if (!JsTableActiveCellEditor) return;
  JsTableActiveCellEditor.focus();
  var oTbl = JsTableActiveCellEditor;
  for (var i=0; i<4; i++) {
    oTbl = oTbl.parentNode;
    if (!oTbl) return;
  }
  //.parentNode.parentNode.parentNode.parentNode;
  var oJsTable = window['_'+oTbl.id];
  oJsTable._onmove = false;
  JsTableActiveCellEditor = null;
};
JsTable.prototype._setCellEditorFocus = function(oCellEditor) {
  JsTableActiveCellEditor = oCellEditor;
  setTimeout('JsTableSetCellEditorFocus()',0);
};
JsTable.prototype.setFocus = function(bGetFocus) {
  if (this.hasFocus == bGetFocus) return;
  if (this.row < 1 || this.col < 0) return;
  var o = this.getObjectsOnCell(this.row,this.col);
  if (bGetFocus) {
    this.hasFocus = true;
    var iCont = o.column.containsEditor(o.cell,o.cellEditor);
    if (iCont ^ -1) //o.column.constructor==JsTableColumnBoolean || !o.cell.contains(o.cellEditor)
      o.column.setEditorOnArrive(o.cellEditor,o.cell,this);
    o.cell._onclick = false;
    o.cell._keydown = false;
    if (this._oncellchange) this.oncellchange();
    this._oncellchange = false;
    this._setCellEditorFocus(o.cellEditor);
  } else {
    this.hasFocus = false;
    if (o.column.containsEditor(o.cell,o.cellEditor)) {
      if (this.onEdit) this.setOnCommit();
      o.column.setEditorOnLeave(o.cellEditor,o.cell,this);
      if (o.column.containsEditor(o.cell,o.cellEditor)) //such as checkbox, Link
        if (!this._onblur) {
           if (o.cellEditor.blur)  o.cellEditor.blur;
        } else {
          this._onblur = false;
        }
    }
  }
};
JsTable.ENTER_STAY = 0;
JsTable.ENTER_MOVE_DOWN = 1;
JsTable.ENTER_MOVE_RIGHT = 2;
} /**************** if (JsTableNavFamily) *****************************/







Hello this is editable, navigatable and submitable table. Click on the table to give it the focus.

The decimal point of numbers in the table is represented by comma ( , ) not period ( . ).
The date time format is 'dd-mm-yyyy hh:nn:ss'





  
    
    
  

  
Button 'Submit' is to submit the content of table to web server.
  Button 'Add Row' is to add row in the table



 


How To Edit and Navigate :

border-color:black; background-color:#c0c0c0; color:#404000; height:150px; width:775px;
overflow:scroll; padding:8px; text-align:justify">
To give focus to table, click on the table. The cell on which we click,
automatically become the active cell. The active cell is the cell in which
we can edit its content. If usually its cell
editor is hidden for that cell, when the cell is active, it reveals its
cell editor, so we can edit it.



Navigation:

    We can move the active cell by pressing the arrow
keys on keyboard by intuitive direction. We can also click on a cell,
if we want that cell become active.



Editing:

    To edit the cell's content needs some steps which is
different for different cell editor. I will explain for each cell
editor.


This software is licensed under GNU Lesser General Public License as published by the
Free Software Foundation; either version 2.1 of the License or (at your option) any later version.

See the JsTable's source and the
documentation.

Send the bugs report to almulyana@yahoo.com.

Copyright © 2005 AT Mulyana


 
           
         
  
JsTable20050725.zip( 34 k)