Table in JavaScript : Table Grid : GUI Components JAVASCRIPT DHTML TUTORIALS


JAVASCRIPT DHTML TUTORIALS » GUI Components » Table Grid »

 

Table in JavaScript



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Strict//EN">
<html>
<head>

<!-- JsTable.js -->
<script language=JavaScript>
/****
    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 = parseFloatnavFamily.substring(navFamily.indexOf('opera')+6,
      navFamily.length) );
    if (ver >= 7.5navFamily = 'Opera7';
    else navFamily = '';
  else if (navFamily.indexOf('msie')!=-1) {
    var ver = parseFloatnavFamily.substring(navFamily.indexOf('msie')+5,
      navFamily.length) );
    if (ver >= 6.0navFamily = 'IE6';
    else navFamily = '';
  else if (navFamily.indexOf('gecko')!=-1) {
    var ver = parseFloatnavFamily.substring(navFamily.indexOf('gecko')+6,
      navFamily.length) );
    if (ver >= 20030624navFamily = '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 (!foundvalid=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 (!foundvalid=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 (!bValidreturn 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%4bValid = bValid && (iDay <= 28);
      else bValid = bValid && (iDay <= 29);
    else {
      bValid = bValid && (iDay <= arMonthlong[iMonth]);
    }
  }
  
  if (bValid) {
    if (iDay < 10iDay = '0' + iDay;
    if (iMonth < 10iMonth = '0' + iMonth;
    iYear = '0000'.substring(0(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*dddd)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 (!bValidreturn bValid;
  else
    return false;
  
  //Checks the date part
  var sDate = ar[2].isDate(sFormat);
  if (!sDatereturn 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 (bValidbValid = (iMinute >= 0&& (iMinute < 60);
  if (bValidbValid = (iSecond >= 0&& (iSecond < 60);
  
  if (bValid) {
    if (iHour < 10iHour = '0' + iHour;
    if (iMinute < 10iMinute = '0' + iMinute;
    if (iSecond < 10iSecond = '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.0sSign = '';
  }
  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 (!sNumbersNumber = '0';
  }
  if (fracDigits) {
    fracDigits = parseInt(fracDigits);
    fracDigits = (isNaN(fracDigits): fracDigits);
    if (!sDecsDec = '0';
    sDec = Math.roundparseFloat('0.'+sDec)* Math.pow(10,fracDigits) ) '';
    while (sDec.length < fracDigitssDec = '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 > 0arNum[arNum.length= sNumber;
  arNum.reverse();
  if (sDecsDec = 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 (alterPointDecToPeriodreturn 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<10day='0'+day;
  if (month<10month='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<10day='0'+day;
  if (month<10month='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<10day='0'+day;
  if (month<10month='0'+month;
  if (year<10year='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<10hour='0'+hour;
  if (minute<10minute='0'+minute;
  if (second<10second='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 (!ddmmyyyyreturn;
  var dates = ddmmyyyy.split('-');
  this.setFullYearparseInt(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 (!mmddyyyyreturn;
  var dates = mmddyyyy.split('-');
  this.setFullYearparseInt(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.setFullYearparseInt(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 (!JsTableCellEditorSelectreturn;
  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<arElms.length; i++) {
      if (arElms[i].getAttribute('name') == this.inputNamereturn 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<arText.length; i++) {
      oText = document.createTextNode(arText[i]);
      oCell.appendChild(oText);
      if (i<arText.length-1) {
        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 (oCellEditoroCellEditor.value = this.getShownValue(oCell,oJsTable);
    else this._setShownValuethis._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.oldValIfInvalidval = 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._setShownValuethis._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.denominationreturn 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.denominationshownVal = 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 (valreturn 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 (!arValuesSentarValuesSent = [];
  if (!arValuesShownarValuesShown = [];
  for (var i=0; i<arValuesSent.length; 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.optionsreturn 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<oCellEditor.length; i++)
        if (oCellEditor.options[i].value==valbreak;
      oCellEditor = oCell.appendChild(oCellEditor);
      oCellEditor.selectedIndex = i;
      if (oCell._keydownoCellEditor._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._keydownoCellEditor._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.optionsval = this.getInputElm(oCell).value; //Text box
    oCell.removeChild(oCellEditor);
    this.getInputElm(oCell).value = val;
    this._setShownValuethis._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 (validreturn 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 (oCellEditoroCellEditor.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 (validreturn 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 (oCellEditoroCellEditor.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<arElms.length; i++) {
      if (arElms[i].getAttribute('name') == this.inputNamereturn 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.firstChildoLink.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 (!sHrefsHref = 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.cloneNodeidentifier = 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<document.styleSheets.length; i++) {
      o = document.styleSheets[i][cssRules];
      for (j=0; j<o.length; j++) {
        selectorText = o[j].selectorText.toLowerCase();
        if (selectorText=='.jstable' || selectorText=='table.jstable') {
          noJsTableStyle = false;
          break;
        }
      }
      if (!noJsTableStylebreak;
    }
    if (!document.styleSheets.lengthhasMethodInsert = 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==1document.write('<'+'style>n');
        document.write(selector + '{' + sRule + '}n');
        if (iPhase==2document.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 1return 1;
      case 2return 4;
      case 3return 2;
    }
  }
  function JsTableGeckoEventSrcElement() {
    return this.target;
  }
  function JsTableGeckoEventFromElement() {
    return this.relatedTarget;
  }
  function JsTableGeckoEventToElement() {
    return this.relatedTarget;
  }
  function JsTableGeckoEventReturnValue(bVal) {
    if (!bValthis.preventDefault();
  }
  function JsTableGeckoEventCancelBubble(bVal) {
    if (bValthis.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 == oNodereturn true;
      oNode = oNode.parentNode;
    }
    return false;
  }

  JsTableGetKeyCode = function(e) {
    if (e.type=='keypress') {
      if (e.charCodereturn 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 113if (JsTableKeyCodeOnKeyDown==81return 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==222return 39//single quote ( ' )
          return 39000;  //Right Arrow
        case 40:
        case 57386return 40000;  //Down Arrow
        case 57395return 46000;  //Delete
        case 57381return 36000;  //Home
        case 57382return 35000;  //End
        default   return e.keyCode;
      }
    else {
      JsTableKeyCodeOnKeyDown = e.keyCode;
      switch (e.keyCode) {
        case 57346return 113//F2
        case 57387return 37;  //Left Arrow
        case 57385return 38;  //Up Arrow
        case 57388return 39;  //Right Arrow
        case 57386return 40;  //Down Arrow
        case 57395return 46;  //Delete
        case 57381return 36;  //Home
        case 57382return 35;  //End
        default   return e.keyCode;
      }
    }
  };
else //IE 6
  JsTableGetKeyCode = function(e) {
    return e.keyCode;
  };
}

/************** Event Handler ********************/
function JsTableGetObjectsOnEvent(sTagName,e)
{
  if (!ee = 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 (!oTargetreturn null;
  }
  if (oTarget.nodeName=='TD' || oTarget.nodeName=='TH') {
    objs.cellEditor = null;
    objs.cell = oTarget;
  else {
    objs.cellEditor = oTarget;
    objs.cell = oTarget.parentNode;
  }
  if (!objs.cellreturn null;
  objs.row = objs.cell.parentNode;
  if (!objs.rowreturn null;
  objs.tbl = (objs.row.parentNode ? objs.row.parentNode.parentNode : null);
  if (!objs.tblreturn 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 (!ee = window.event;
  var oTarget = e.srcElement;
  var oTbl = oTarget;
  while (oTbl.nodeName!='TABLE') {
    oTbl = oTbl.parentNode;
    if (!oTblreturn;
  }
  var oRow = oTbl.rows[0];
  var bOnEdge = false;
  if (oTarget.tagName=='TH') {
    if (e.offsetX==&& 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 (!ee = window.event;
  var oTbl = e.srcElement;
  if (oTbl.tagName!='TABLE') return;
  if (!e.fromElementreturn;
  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 + + oRow.cells[1].offsetWidth;
    var iCol = 1;
    while (e.offsetX > iLeft) {
      iCol++;
      if (iCol==oRow.cells.lengthbreak;
      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 (!ee = 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.stylethis.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.releaseCapturedocument.releaseCapture();
  else {
    document.removeEventListener('mouseup',JsTableOnResizeOnMouseUp,true);
    document.removeEventListener('mouseout',JsTableOnResizeOnMouseOut,true);
  }
  JsTableColToResize = -1;
  JsTableOffsetXstartToResize = -1;
  JsTableObjectTblOnResize = null;
  if (bHasFocusoJsTable.setFocus(true);
}
function JsTableOnResizeOnMouseUp(e)
{
  if (!JsTableObjectTblOnResizereturn;
  if (!ee = window.event;
  var dx = e.screenX - JsTableOffsetXstartToResize;
  var oJsTable = window['_'+JsTableObjectTblOnResize.id];
  var bHasFocus = oJsTable.hasFocus;
  if (bHasFocusoJsTable.setFocus(false);
  var oCol = oJsTable.tableModel.columns[JsTableColToResize];
  oCol.width += dx;
  if (oCol.width < 20oCol.width = 20;
  var oTbl = oJsTable.table;
  for (var i=0; i<oTbl.rows.length; 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 (!JsTableObjectTblOnResizereturn;
  if (!ee = window.event;
  if (!e.toElement) {
    var oJsTable = window['_'+JsTableObjectTblOnResize.id];
    var bHasFocus = oJsTable.hasFocus;
    JsTableStopDragOnResize(oJsTable,bHasFocus);
  }
}

function JsTableOnMouseDown(e)
{
  if (JsTableColToResize >= 0) {
    if (!ee = 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 (!oreturn;
  var iRow = o.row.rowIndex;
  var iCol = o.cell.cellIndex;
  if (iRow < 1) {
    if (o.tbl.rows.length <= 1return;
    iRow = 1;
  }
  if ('|TEXTAREA|INPUT|SELECT|A|'.indexOf('|'+o.target.nodeName+'|')!=-1o.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.cellEditoro.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 (!oreturn;
  o.jsTable.setOnEdit();
}

function JsTableOnBlur(e)
{
  var o = JsTableGetObjectsOnEvent('|TEXTAREA|INPUT|SELECT|A|',e);
  if (!oreturn;
  if (o.jsTable._onclickIE6)
    o.jsTable._onclickIE6 = (o.jsTable._onclickIE6[0]!=o.row.rowIndex
      || o.jsTable._onclickIE6[1]!=o.cell.cellIndex);
  if (o.jsTable._onmoveo.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 (!oreturn;
  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.onEditbreak;
    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 (!bRetValreturn 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<oRow.cells.length-1)?(iCol+1):iCol )};
    case 40//Down
    case 40000:
      return {row: ( (iRow<oTbl.rows.length-1)?(iRow+1):iRow ), col: iCol};
  }
}

function JsTableOnKeyDown(e)
{
  var o = JsTableGetObjectsOnEvent('|TEXTAREA|INPUT|SELECT|A|',e);
  if (!oreturn;
  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.onEdito.jsTable.setOnEdit();
      else {
        o.jsTable.setOnCommit();
        var keyCode = 0;
        if (o.jsTable.tableModel.enterAfterEdit == JsTable.ENTER_MOVE_DOWNkeyCode = 40;
        if (o.jsTable.tableModel.enterAfterEdit == JsTable.ENTER_MOVE_RIGHTkeyCode = 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 = falsebreak;
    case 113//F2
      o.jsTable.setOnEdit();
      bRetVal = falsebreak;
    case 27// Escape
      o.jsTable.setOnCommit();
      bRetVal = falsebreak;
    }
  }
  
  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 (!oreturn;
  o.event.returnValue = false;
  o.cellEditor.checked = o.cell._checked;
}

function JsTableOnCheckboxKeyDown(e)
{
  var o = JsTableGetObjectsOnEvent('|INPUT|',e);
  if (!oreturn;
  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 (!oreturn;
  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 (!oreturn;
  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 (!oreturn;
  
  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 == || keyCode == //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._nocancelclickthis._nocancelclick = false;
  else return false;
}
var JsTableOnLinkMouseUpJsTableObject = null;
var JsTableOnLinkMouseUpLinkObject = null;
function JsTableOnLinkMouseUpOpera7(e) {
  var o = JsTableGetObjectsOnEvent('|A|',e);
  if (!oreturn;
  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 (!ee = window.event;
  if (e.keyCode==13this._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.lengthcolumns = [];
  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 (oldValIfInvalidthis.oldValIfInvalid = true;
  else this.oldValIfInvalid = false;
  
  if (phpStyle) {
    for (var i=0;i<columns.length;i++columns[i].inputName += '[]';
  }
  
  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' || !sIdreturn 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<columns.length; 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 (!oNextSiblingoNextSibling = null;
  oTbl = oParent.insertBefore(oTbl,oNextSibling);
  window[sId= oTbl;
  window['_'+sIdthis;
  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 (oCelloCell = oCell.cells[iCol];
  var oCellEditor = oColumn.getCellEditor(oCell,this);
  if (!oCellEditoroCellEditor = 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 (!oCellreturn;
  JsTableRemoveAllText(oCell);
  oCell.appendChild(document.createTextNode(sHeader+""));
};

JsTable.prototype.setValue = function(val, iRow, iCol) {
  if (iRow < || iCol < 0return;
  var o = this.getObjectsOnCell(iRow,iCol);
  if (!o.cellreturn;
  var oCellEditor = null;
  if (o.cellEditorif (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 < 1return;
  var oRow = oTbl.rows[iRow];
  if (!oRowreturn;
  var oCell = oRow.cells[iCol];
  if (!oCellreturn;
  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 (!iRowiRow = oTbl.rows.length;
  iRow = parseInt(iRow);
  if (isNaN(iRow)) return;
  if (iRow > oTbl.rows.length || iRow < 1iRow = oTbl.rows.length;
  if (!this.tableModel.withPrimaryKeyprimaryKey = iRow;
  
  var arColKey = [];
  var i, j = 0;
  var oRow = oTbl.insertRow(iRow);
  for (i=0; i<arColumn.length; 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<oTbl.rows.length; i++) {
      for (j=0; j<arColKey.length; 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<this._keys.length; 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<args2.length; 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 < || iRow >= oTbl.rows.lengthreturn;
  var bHasFocus = this.hasFocus;
  if (iRow == this.row && bHasFocusthis.setFocus(false);
  oTbl.deleteRow(iRow);
  var arColumn = this.tableModel.columns;
  if (!this.tableModel.withPrimaryKey) {
    for (var j=0; j<arColumn.length; j++) {
      if (typeof arColumn[j].setPrimaryKey!='function') continue;
      for (var i=iRow; i<oTbl.rows.length; i++) {
        var oCell = oTbl.rows[i].cells[j];
        arColumn[j].setPrimaryKey(oCell,i);
      }
    }
  }
  for (var j=0; j<arColumn.length; j++) {
    if (typeof arColumn[j].setRowIndex!='function') continue;
    for (var i=iRow; i<oTbl.rows.length; i++) {
      var oCell = oTbl.rows[i].cells[j];
      arColumn[j].setRowIndex(oCell);
    }
  }
  
  if (iRow >= oTbl.rows.lengthiRow = oTbl.rows.length-1;
  if (iRow > 0this.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<arColumn.length; 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 (!iRowiRow = 1;
  iRow = parseInt(iRow);
  if (isNaN(iRow)) return;
  if (iRow < || iRow >= oTbl.rows.lengthreturn;
  
  var iLength = 0;
  if ((typeof val != 'object') || (typeof val.length != 'number')) {
    val = [val];
    iLength = 1;
  else 
    iLength = val.length;
  if (iRow+iLength > oTbl.rows.lengthiLength = oTbl.rows.length - iRow;
  
  var oCell = oTbl.rows[iRow].cells[0];
  var bKeyExist = false;
  var arInputs = oCell.getElementsByTagName('INPUT');
  for (var i=0; i<arInputs.length; i++)
    if (arInputs[i].getAttribute('name')==sKeyName) {
      bKeyExist = true;
      break;
    }
  if (bKeyExist) {
    for (var i=0; i<iLength; i++) {
      oCell = oTbl.rows[iRow+i].cells[0];
      arInputs = oCell.getElementsByTagName('INPUT');
      for (var j=0; j<arInputs.length; 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<oTbl.rows.length; i++) {
      oCell = oTbl.rows[i].cells[0];
      var oInput = document.createElement('INPUT');
      oInput.type = 'hidden';
      oInput.setAttribute('name',sKeyName);
      if (i >= iRow && i < joInput.value = val[i-iRow];
      oCell.appendChild(oInput);
    }
  }
};

JsTable.prototype.setActiveCell = function(iRow, iCol) {
  if (iRow < || iRow >= this.table.rows.length
     || iCol < || iCol >= this.tableModel.columns.lengthreturn;
  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 > && 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.onEditreturn;
  if (this.row < || this.col < 0return;
  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.onEditreturn;
  if (this.row < || this.col < 0return;
  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 (!JsTableActiveCellEditorreturn;
  JsTableActiveCellEditor.focus();
  var oTbl = JsTableActiveCellEditor;
  for (var i=0; i<4; i++) {
    oTbl = oTbl.parentNode;
    if (!oTblreturn;
  }
  //.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 == bGetFocusreturn;
  if (this.row < || this.col < 0return;
  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._oncellchangethis.oncellchange();
    this._oncellchange = false;
    this._setCellEditorFocus(o.cellEditor);
  else {
    this.hasFocus = false;
    if (o.column.containsEditor(o.cell,o.cellEditor)) {
      if (this.onEditthis.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) *****************************/
</script>
<style><!--
/*
.JsTable .cell-focus {
  background-color: red;
}
*/
--></style>
<script language=JavaScript>
<!--
var g_oJsTable;
function setValues(iRow, str, num, denNum, bool, opt, date, datetime )
{
  //alert(iRow + ' : ' + str + ',' + num + ',' + denNum + ',' + bool + ',' + opt + ',' + date);
  g_oJsTable.setValue(str,      iRow, 0);
  g_oJsTable.setValue(num,      iRow, 1);
  g_oJsTable.setValue(denNum,   iRow, 2);
  g_oJsTable.setValue(bool,     iRow, 3);
  g_oJsTable.setValue(opt,      iRow, 4);
  g_oJsTable.setValue(date,     iRow, 5);
  g_oJsTable.setValue(datetime, iRow, 6);
}
function addRow()
{
  g_oJsTable.insertRow([]);
  if (g_oJsTable.row > 0g_oJsTable.setFocus(true);
  else g_oJsTable.setActiveCell(1,g_oJsTable.col);
  
}
window.editedRowIndex = 0;
function editRow(iRow)
{
  var win = window.open('./JsTable-selectValue.htm', 'JsTableSelectValues',
    'left=40,top=40,height=400,width=720,resizable=1,scrollbars=1');
  if (!win.openerwin.opener = window;
  window.editedRowIndex = iRow;
}
function deleteRow(iRow)
{
  g_oJsTable.deleteRow(iRow);
}

function showTable()
{
  if (!JsTableNavFamily) { //If the browser doesn't support JsTable
    document.open('text/html','replace');
    document.write("<h3>Your browser does not support</h3>");
    document.write("Use the following browsers:<ul>");
    document.write("<li>Gecko browsers which is equivalent with or newer than Mozilla 1.4/Netscape 7.1</li>");
    document.write("<li>Opera 7.5 or newer</li>");
    document.write("<li>Internet Explorer 6</li></ul>");
    document.write("Some versions is still buggy. Have the best browser.");
    document.close();
    return;
  }
  
  var oSbm = document.getElementById('submit');
  var align;
  var columns = [
    new JsTableColumnString('String','string',120),
    new JsTableColumnNumber('Number','number',75),
    new JsTableColumnNumber('Denominated Number','denNumber',75,'right',true,2),
    new JsTableColumnBoolean('Boolean','boolean',50),
    new JsTableColumnOptions'Options','options',100,align,
      new JsTableOptionValues(['Satu','Dua','Tiga'],['_Satu','_Dua','_Tiga']) ),
    new JsTableColumnDate('Date','date',70,'center'),
    new JsTableColumnDateTime('Date Time','datetime',140,'center',true),
    new JsTableColumnLink('','link',50,'center','Edit',
      'javascript:editRow(__ROW__)'),
    new JsTableColumnLink('','link',50,'center',document.createTextNode('Delete'),
      'javascript:deleteRow(__ROW__)')
  ];
//  JsTableColumnLink(columnName,inputName,width,align,identifier,href)
  var oTableModel = new JsTableModel(columns,true,'.','d-m-y',true);
  oTableModel.enterAfterEdit = JsTable.ENTER_MOVE_RIGHT;
  oTableModel.isCellEditable = function(iRow,iCol) {
    //if (iRow==1) return false;
    return true;
  };
  g_oJsTable = new JsTable('trans',oTableModel,
    document.getElementById('showTable'),oSbm);
  
  g_oJsTable.insertRow(['aaa',1234.8,22456,true,'Tiga','9-4-2005','31-7-1978 21:0:0']);
  g_oJsTable.insertRow(['yaa',-.98,'234x6',false,'Dua','','27-1-1981 9:0:0']);
  for (var i=1; i<5; i++) {
    g_oJsTable.insertRow([]);
  }
}
//-->
</script>
</head>
<body onload='showTable()' style="width:90%">
<p>Hello this is editable, navigatable and submitable table. Click on the table to give it the focus.
<br>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'</p>
<noscript><h2>Turn on your JavaScript!!</h2></noscript>
<form method=post action='JsTable.php' target='submittedValues'>
<div id=showTable align=center style="width:100%">
  <div id=submit>
    <input type=submit value=Submit>
    <input type=button value='Add Row' onclick="addRow()">
  </div>
  <div>Button 'Submit' is to submit the content of table to web server.
  Button 'Add Row' is to add row in the table</div>
</div>
</form>

<div>&nbsp;</div>
<div align=center>
<h4 style="width:791px; margin:0px"><div align=left>How To Edit and Navigate :</div></h4>
<div align=left style="font-family:sans-serif;font-size:13px; border-style:solid; border-width:1px;
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.<br>
<br>
Navigation:<br>
&nbsp;&nbsp;&nbsp; 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.<br>
<br>
Editing:<br>
&nbsp;&nbsp;&nbsp; To edit the cell's content needs some steps which is
different for different cell editor. I will explain for each cell
editor.<br>
<ul>

  <li><u>Textbox</u> (element <span
 style="font-family: monospace; font-size: 12px;">&lt;TEXTAREA&gt;</span>
or <span style="font-family: monospace; font-size: 12px;">&lt;INPUT
type=text&gt;</span>)<br>
To edit, press Enter. Then we will go into the state, we call it <span
 style="font-style: italic;">editing state</span>. In editing state,
the text cursor will appear and thus we can edit the cell's content.
When editing state, the arrow keys cannot be used to navigate but used
to move text cursor instead. To end the editing state, press Enter
again. Another way to go into editing state is by pressing F2 (on
Opera, F2 has the meaning for the browser itself). To end the editing
state, press Esc. Pressing any valid character will also set the JsTable
into editing state automatically (as of version 0.4.5).
We can also double click on a cell (may be triple
clickif we want to edit the cell. But to end the editing state, still
use the keyboard. Clicking on another cell, when the active cell is
edited, will end the editing state of current active cell and move the
active cell to the cell has just been clicked. When on the number column,
you may only press the valid character for a number. So do the date column
and datetime column.</li>
  <li><u>Checkbox</u> (element <span
 style="font-family: monospace; font-size: 12px;">&lt;INPUT
type=checkbox&gt;</span>)<br>

To change the state of the checkbox, press Enter or Space. Clicking on
the cell will also change the checkbox' state.</li>
  <li><u>Combobox</u> (element <span
 style="font-family: monospace; font-size: 12px;">&lt;SELECT&gt;</span>)<br>
To edit, press Enter and then going into editing state. Use up arrow
and down arrow, to change the option. Press enter again, to end the
editing state. Key F2 can also be used but key Esc may not be useful in
all browsers. Esc may reset the option. Another way to change the
option, when in editing state, press Alt+down_arrow, the the combobox
will reveal its option, choose option by pressing down arrow or up
arrow and then press Enter to end the editing state. This way doesn't
run perfectly in all browsers.<br>
If you want to use mouse, do with usual steps: click on the combobox
and choose the option.</li>
  <li><u>Link</u><br>
The Link cannot be edited but only execute its link's target. To
execute its target, press Enter or click the Link.<br>
  </li>
</ul>

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 optionany later version.<br>
See the JsTable's <a href='./JsTable.js' target='_blank'>source</a> and the
<a href='./JsTable_Documentation.html' target='_blank'>documentation</a>.<br>
Send the bugs report to <a href="mailto:almulyana@yahoo.com">almulyana@yahoo.com</a>.
</div>
<small>Copyright &copy; 2005 AT Mulyana</small>
</div>

</body>
</html

           
       

Download : Download nav_JsTable20050725.zip nav_JsTable20050725.zip


-

Leave a Comment / Note


 
Verification is used to prevent unwanted posts (spam). .

Follow Navioo On Twitter

JAVASCRIPT DHTML TUTORIALS

 Navioo GUI Components
» Table Grid