﻿// JScript File
var objList = new Object();
var fncList = new Object();

// todo: TableEdit should be shown/hidden and moved/sized to appear over the cell

function text2inputvalue(input, text){
    var tmp = input.value;
    input.value = text;
    var ret = input.value;
    input.value = tmp;
    return ret;
}

function Exec(funct, params)
{
    if (funct && funct != "")
        try {
            if (typeof (funct) == "string") {
                if (funct.indexOf("(") == -1) 
                {
                    if (fncList[funct] == null) fncList[funct] = eval(funct);
                    return (fncList[funct])(params);
                }
                else return eval(funct);
            }
            else if (typeof (funct) == "function")
                return (funct)(params);
        } catch (err) { OnErr({msg: err.message, val: funct}); }
    return null;
}

function ExecEx(obj, prp, params)
{
    if (!obj) return false;

    if (obj.getAttribute && obj.getAttribute(prp))
        return Exec(obj.getAttribute(prp), params);
    else
        return Exec(obj[prp], params);
}


function disableCtrl(ctrl, disable)
{
    if (ctrl == null)
        return;
        
    var type = fieldType(ctrl); 
    if (type == fType.DDEx) return DDExDisable(ctrl.id, disable);       
    
    if(Browser() == "ie")
    {
        if (ctrl.disabled == null) return;
    	ctrl.disabled = disable;
    }
    else if(Browser() == "ff")
    {
        if(ctrl.setAttribute == null) return;
        if (!disable)
            ctrl.removeAttribute("disabled");
        else
            ctrl.setAttribute("disabled", "disabled");
    }


	if (disable)
		ctrl.tabInd = ctrl.tabIndex;
	else
		ctrl.tabIndex = ctrl.tabInd;

    for(var i=0; ctrl.childNodes && i<ctrl.childNodes.length; i++)
        if(ctrl && !eq(ctrl.tagName, "select"))
            disableCtrl(ctrl.childNodes[i], disable);
}

var fType = { None:0, Text:1, Select:2, Check:3, Textarea:4, Datetime:5, Money:6, DDEx:7, tinyMCE:8, Html:9, Multsel:10, Custom:11, Delete:12 }

function fieldType(input)
{
    if(typeof(input.getAttribute) == "undefined")return fType.None;
    
    var tag = input.tagName;
    var typ = input.getAttribute("type");
    var edt = input.getAttribute("cnEditType");

    if(eq(edt,"TINYMCE"))  return fType.tinyMCE;
    if(eq(tag,"TEXTAREA")) return fType.Textarea;
    if(eq(tag,"SELECT"))   return fType.Select;
    if(eq(edt,"DDEX"))     return fType.DDEx;
    if(!eq(tag,"INPUT"))   return fType.None;
    if(eq(edt,"MONEY"))    return fType.Money;
    if(eq(edt,"DATETIME")) return fType.Datetime;
    if(eq(typ,"TEXT"))     return fType.Text;
    if(eq(typ,"CHECKBOX")) return fType.Check;
	return fType.None;
}

function fldType(name)
{
    if(name == null) return fType.None;
    switch (name.toUpperCase())
    {
        case "BOOL":     return fType.Check;
        case "DATETIME": return fType.Datetime;
        case "TEXT":     return fType.Text;
        case "READONLY": return fType.None;
        case "TEXTAREA": return fType.Textarea;
        case "MONEY":    return fType.Money;
        case "HTML":     return fType.Html;
        case "DELETE":   return fType.Delete;
        case "CUSTOM":   return fType.Custom;
        case "MULTSEL":  return fType.Multsel;
        case "PULLDOWN": return fType.Select;
        case "DDEX":     return fType.DDEx;
    }
    return fType.None;
}


function Quote(str)
{
    return ("" + str).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;");;
}


function ClearInput(input)
{
    if(input == null) return;
    var type = fieldType(input);
    if (type == fType.Check)
    	input.checked = false;
    else if (type == fType.Select)
    	input.value = input.getAttribute("cnDefVal") ? input.getAttribute("cnDefVal") : "";
    else if (type == fType.DDEx)
        DDExClear(input.id); // SRE only
    else
    	try { input.value = input.getAttribute("cnDefVal") ? input.getAttribute("cnDefVal") : ""; input.innerHTML = input.getAttribute("cnDefVal") ? input.getAttribute("cnDefVal") : ""; } catch (ex) { } 
}


//----------------------------------------------------- Transport staff ----------------------------------------------------

var Progress;
var webServiceCalls = 0;
var TryToSendBatch = null;
var theBatch = new Array();
var resFunct = new Array();

function CustServerCall(cmdCode, objName, args, onRes)
{
    if(onRes) resFunct.push(onRes);
    ServerCall("Custom", new Object(), {cmdCode: cmdCode, objName: objName, args: args, onRes: resFunct.length - 1});
}

//=== DON'T CALL THE FOLLOWING FUNCTION FROM OUTSIDE OF PAT!!! ===================
function ServerCall(cmdCode, obj, args)
{
    if(!eq(cmdCode,"Custom") && ExecEx(obj, "onServerCall", {obj: obj, cmdCode: cmdCode, args: args}) == false || obj.sleep == true) return;
    if(obj && obj.Progress) obj.Progress.Show(true);
	theBatch.push({cmdCode: cmdCode, objName: obj.name, args: args});
	window.clearTimeout(TryToSendBatch);
	TryToSendBatch = window.setTimeout(SendBatch, 1);
}
//================================================================================

function SendBatch()
{
    if (theBatch.length == 0) return;
	Tables.BatchCallWebService(theBatch, OnSendBatchRes, OnServiceError);
	theBatch.length = 0;
	++webServiceCalls;
    if (Progress && webServiceCalls == 1) Progress.Show(true);
}

function OnSendBatchRes(res)
{
	if (res != null)
	{
	    for (var i = 0; i < res.length; i++)
	        if (eq(res[i].cmdCode,"Custom"))
	            try { resFunct[res[i]["args"].onRes](res[i]); } catch (err) { OnErr({msg: err.message, val: res[i].objName}); }
	        else {
	            var obj = objList[res[i]["objName"]];
	            if (ExecEx(obj, "onServerRes", AddHash(res[i], "obj", obj)) != false) {
	                try { obj.OnServiceRes(res[i]); } catch (err) { OnErr({msg: err.message}); }
	                ExecEx(obj, "onDataLoaded", AddHash(res[i], "obj", obj)); // perform after objects process results
	                if(obj && obj.Progress) obj.Progress.Show(false);
	            }
	        }
	        --webServiceCalls;
	        if (Progress && webServiceCalls == 0 && theBatch.length == 0) Progress.Show(false);
	}
}

function OnServiceError(err)
{
	if (err != null) OnErr({ msg: err._message }); // + "<br>" + error._stackTrace);
	--webServiceCalls;
    if(Progress && webServiceCalls == 0) Progress.Show(false);
}


//----------------------------------------------------- Error handling ---------------------------------------------------------------------

var OnErrorCustom = null;
function OnError(errorText)
{
    var errTxt = $get("ErrorText");
    var errWnd = typeof(placeHolderID) != "undefined" && placeHolderID != null ? $find(placeHolderID) : null;
    if(OnErrorCustom ? Exec(OnErrorCustom, errorText) : true)
        { if (errWnd && errTxt) {errTxt.innerHTML = errorText; errWnd.show();} else alert(errorText); }
    return false;
}

var OnErrCustom = null;
function OnErr(p)
{
    p.stack = CallStack();
    if(OnErrCustom ? Exec(OnErrCustom, p) : true)
        OnError((p.obj && p.obj.name ? p.obj.name + " : " : "" ) + p.msg + (p.val != null && p.val != "" ? " : " + p.val : ""));
    return false;
}

window.onerror = function(msg, file, line){
  return OnErr({msg: msg, file: file, line: line});
}


//----------------------------------------------------- Notifications ---------------------------------------------------------------------
function DataChangeNotify(List, params)
{
    var names  = (List != null && List != "" ? List.replace(/\s/g, "").split(",") : new Array());
    for(var i=0; i<names.length; i++)
        if(objList[names[i]]) objList[names[i]].OnDataChangeNotification(params);
}

function RowChangeNotify(List, params)
{
    var names  = (List != null && List != "" ? List.replace(/\s/g, "").split(",") : new Array());
    for(var i=0; i<names.length; i++)
    {
        var parts = names[i].split("/");
        var paramsCurr = CloneHash(params);
        if(parts.length > 1) paramsCurr = AddHash(paramsCurr, "rowidname", parts[1]);
        if(objList[parts[0]]) objList[parts[0]].OnRowChangeNotification(paramsCurr);
    }
}

//---------------------------------------------- PAT Object stuff ----------------------------------------------

var PatObjType = { Table:0, SRE:1, DD:2, DDEx:3, List:4, ACmplt:5, Tabs:6, PopUp:7 }

function PatObj_Sleep(name, sleep)
{
    if(objList[name]) objList[name].sleep = sleep;
}

function PatObj_WakeUp(name, args)
{
    if(objList[name] && objList[name].sleep)
    {
        objList[name].sleep = false;
        if (objList[name].Refresh) objList[name].Refresh(args);
    }
}

function PatObj_isInited(name, type)
{
    return (objList[name] != null && (type == null || eq(objList[name].type, type)))
}

function PatObj_Init(type, name, args, prms)
{
    if(args == null) args = new Object();
    if(prms == null) prms = new Object();
    //if(objList[name]) - TO DO
    objList[name] = new Object();
    objList[name].type = type;
    
    PatObj_LoadGlobalPrms(name, prms);
    
    switch(type)
    {
        case PatObjType.Table:  TableEditor(name, args, prms);  break;
        case PatObjType.SRE:    RowEditor(name, args, prms);    break;
        case PatObjType.DD:     DropDown(name, args, prms);     break;
        case PatObjType.DDEx:   DropDownEx(name, args, prms);   break;
        case PatObjType.List:   ListsEditor(name, args, prms);  break;
        case PatObjType.ACmplt: AutoComplete(name, args, prms); break;
        case PatObjType.Tabs:   TabsObj(name, args, prms);      break;
        case PatObjType.PopUp:  PopUpObj(name, args, prms);     break;
    }
    
    return objList[name];
}

function PatObj_LoadGlobalPrms(name, prms) // We can't just copy prms to pat obj, becouse same attributes requared additional operations
{
    if(objList[name] == null) return;
    
    if(prms.Prgr == true) objList[name].Progress = new PATProgress(name + "_progress", AddHash(prms, "obj", objList[name]));
    if(prms.sleep != null)objList[name].sleep = prms.sleep;
    objList[name].ReadOnly = (prms.ReadOnly == null ? false : prms.ReadOnly);
    if(prms.multSel != null)objList[name].multSel = prms.multSel;
}

function PatObj_Refresh(name, args)
{
    if(objList[name] && objList[name].Refresh) objList[name].Refresh(args);
}

function PatObj_InitOrRefresh(type, name, args, prms)
{
    if(objList[name] == null)
        PatObj_Init(type, name, args, prms);
    else 
        if(objList[name].Refresh) objList[name].Refresh(args);
    //if(objList[name].type != type) - TO DO
}

function PatObj_SetArgs(name, args, prms)
{
    if (prms) PatObj_LoadGlobalPrms(name, prms);
    if(objList[name] && args) AddHash(objList[name].args, args);
}
function PatObj_GetArgs(name)
{   
    return objList[name].args;
}
//------------------------------------------------ Table Editor ------------------------------------------------
//--------------------------------------------------------------------------------------------------------------

function TableInit(name, args, prms)
{
    return PatObj_Init(PatObjType.Table, name, args, prms);
}

function TableRefresh(name, args)
{
    if(objList[name]) objList[name].Refresh(args);
}

function TableRefreshRow(name, rowId)
{
    if(objList[name]) objList[name].RefreshRow(rowId);
}

function TableSetCurRow(name, rowId)
{
    if(objList[name]) objList[name].SetCurRow(rowId);
}

function TableSort(name, sNames)
{
    if(objList[name]) objList[name].JsSort(sNames);
}

function TableHideRows(name, hide, exeptCur, exeptSel)
{
    if(objList[name]) objList[name].HideRows(hide, exeptCur, exeptSel);
}

function TableGetRowsCnt(name)
{
    return objList[name].rowsTotal != null ? objList[name].rowsTotal : 0;
}

function TableSetCurPage(name, page)
{
    if(objList[name] && objList[name].SetCurPage(page)) objList[name].LoadData();
}

function TableSelectRow(name, rowId, sel)
{
    if(objList[name]) objList[name].SelectRow(rowId, sel);
}

function TableSelectAllRows(name, sel)
{
    if(objList[name]) objList[name].SelectAllRows(sel);
}

function TableClearAllSelection(name)
{
    if(objList[name])objList[name].ClearAllSelection();
}

function TableSetRowsPerPage(name, rowsnum)
{
    if(objList[name] && objList[name].SetPageSize(rowsnum)) objList[name].LoadData();
}

function TableDelRow(name, row, confirm) 
{
    if(objList[name]) objList[name].DelRow(row, confirm);
}

function TableMakeInsert(name)
{
    if(objList[name]) objList[name].InsertRow();
}

function TableMakeInsertEF(name)
{
    if(objList[name]) objList[name].InsertRowEF();
}

function TableClearEF(name)
{
    if(objList[name]) objList[name].ClearEF();
}

function TableShowEF(name, show)
{
    if(objList[name]) objList[name].ShowEF(show);
}

function TableGetCurRowID(name)
{
    if(objList[name]) return objList[name].GetCurrentRowID();
}

function TableGetSelRows(name)
{
    if(objList[name]) return objList[name].GetSelRows();
}

//DO NOT USE. Should be replaced with PatObj_GetArgs
function TableGetArgs(name)
{
    if(objList[name]) return objList[name].args;
}

function TableHideShowCol(name, n, b) {
    if (objList[name]) return objList[name].HideShowCol(n, b);
}

function TableGetCurRowValueByColumn(tableName, columnName) //ask MI
{
    if(objList[tableName]) return objList[tableName].GetCurRowValueByColumn(columnName);
}
function TableGetDataValue(tableName, columnName, rowID)
{
    if(objList[tableName]) return objList[tableName].GetDataValue(columnName, rowID);
}
function TableLock(name, lock, lockIns)
{
    if(objList[name]) objList[name].LockTable(lock, lockIns);
}
function TableBodyLockState(name)
{
    if(objList[name]) return objList[name].LockedBody;
}
function TableInsLockState(name)
{
    if(objList[name]) return objList[name].LockedInsR;
}
function TableEndEdit(name)
{
    if(objList[name] && objList[name].EndEdit) return objList[name].EndEdit(objList[name].theEditor, null, null);
}
//should be removed
function DisableTable(name, disable, disableIns)
{
    if(objList[name]) objList[name].LockTable(disable, disableIns);
}

function TableEditor(name, args, prms)
{
    var self = objList[name];
    if(self == null) return OnErr({msg: "Can't init object", val: name});

    self.name = name;
    self.args = args;

    self.colDefs = new Array();

    self.TableRows = new Array();

    self.curRow = null;
    self.pagesCount = 1;
    
    self.selRowsId = new Object();

    self.topDiv = $get(self.name);
    self.topPager = $get(self.name + "TopPager");
    self.botPager = $get(self.name + "BottomPager");
    self.rowsPP = $get(self.name + "RowsPP");
    self.tabPattern = $get(self.name + "Table");
    self.headRow = $get(self.name + "Header");
    self.gotoPage = $get(self.name + "GoToPage");
    self.rowsCnt = $get(self.name + "RowsCnt");

    if(self.topDiv == null) return;
    if(self.headRow) self.headRow.className = (self.topDiv.getAttribute("TableHeadCss") ? self.topDiv.getAttribute("TableHeadCss") : "def_tablehead_css");
    self.tabPattern.style.display = "none";

    self.onServerCall = self.topDiv.getAttribute("onServerCall");
    self.onServerRes = self.topDiv.getAttribute("onServerRes");
    self.onDataLoaded = self.topDiv.getAttribute("onDataLoaded");
    
    self.SpellCheckInsRow = prms.SpellCheckInsRow == false ? false : true;

    self.tableHolders = new Array();
    for(var i = 1; ; i++)
    {
        var th = $get(self.name + "_TableHolder" + i);
        if(th == null) break;
        self.tableHolders.push(th);
    }
    if(self.tableHolders.length == 0) {
        var tc = document.createElement("div");
        self.tableHolders.push(tc);
        tc.id = self.name + "_TableHolder1";
        tc.style.margin = "0px"; // the developer is not aware that this div will be created so it should have no visual impact.
        tc.style.border = "0px";
        tc.style.padding = "0px";
        self.topDiv.insertBefore(tc, self.tabPattern);
    }
    self.insRowHolder = $get(self.name + "_InsRowHolder");
    
    self.GetSelRows = function ()
    {
        return self.selRowsId;
    }
    
    self.isSelected = function (row)
    {
        for (var id in self.selRowsId)
            if(row.dbid == id)
                return true;
        return false;
    }
    
    self.SetCurPage = function (page)
        {
            if(page == self.currentPage) return false;
            if(page && (!ValidateInt(page) || page < 1 || objList[name].pagesCount < page)) return OnErr({obj: self, msg: "Invalid page number"});
            self.currentPage = page;
            return true;
        }

    self.SetPageSize = function (size)
        {
            if(size == self.PageSize) return false;
            if (size && (!ValidateInt(size) || size < 1)) return OnErr({obj: self, msg: "Invalid page size", val: size});
            self.currentPage = 1;
            self.PageSize = size;
            self.RowsCnt = (self.PageSize == null ? null : self.PageSize * self.tableHolders.length); 
            return true;
        }
    self.SetPageSize(prms.PageSize ? prms.PageSize : self.topDiv.getAttribute("PageSize"));

    self.DataChangeNotifyList = self.topDiv.getAttribute("DataChangeNotifyList");
    self.RowChangeNotifyList = self.topDiv.getAttribute("RowChangeNotifyList");
    
    self.delConfirm = self.topDiv.getAttribute("delConfirm")?self.topDiv.getAttribute("delConfirm"):"";
    
    self.onSelRow = self.topDiv.getAttribute("onSelRow");
    self.onRowSelected = self.topDiv.getAttribute("onRowSelected");
    self.onSelRowsChanged = self.topDiv.getAttribute("onSelRowsChanged");
    self.onNewRow = self.topDiv.getAttribute("onNewRow");

    self.pagerFunction = self.topDiv.getAttribute("PagerFunction");
    self.pagerText = self.topDiv.getAttribute("pagerText");

    self.MaxRows = self.topDiv.getAttribute("MaxRows");
    self.RefreshRowOnChange = eq(self.topDiv.getAttribute("RefreshRowOnChange"), "True");

    self.DbRowId = (self.topDiv.getAttribute("DbRowId") ? self.topDiv.getAttribute("DbRowId") : "id");

    self.OneClickEdit = eq(self.topDiv.getAttribute("OneClickEdit"), "True");

    self.ReadOnly = (self.topDiv.getAttribute("ReadOnly") ? eq(self.topDiv.getAttribute("ReadOnly"),"True") : self.ReadOnly);
    self.DeleteMode = !eq(self.topDiv.getAttribute("DeleteMode"), "False");
    self.LockedBody = false;
    self.LockedInsR = false;

    self.MultiColumnsSorting = eq(self.topDiv.getAttribute("MultiColumnsSorting"), "True");

//    self.tabPattern.className = "def_table_css ";
//    if (self.topDiv.getAttribute("TableCss"))
//        self.tabPattern.className += self.topDiv.getAttribute("TableCss");
    self.tabPattern.className = (self.topDiv.getAttribute("TableCss") ? self.topDiv.getAttribute("TableCss") : "def_table_css");

    self.RowCss = (self.topDiv.getAttribute("RowCss") ? self.topDiv.getAttribute("RowCss") : "def_row_css");
    self.SelRowCss = (self.topDiv.getAttribute("SelRowCss") ? self.topDiv.getAttribute("SelRowCss") : "def_selrow_css");
    self.MouseOverRowCss = (self.topDiv.getAttribute("MouseOverRowCss") ? self.topDiv.getAttribute("MouseOverRowCss") : "def_mouseoverrow_css"); 
    self.RowTip = self.topDiv.getAttribute("RowTip");
    self.RowBackColor = self.topDiv.getAttribute("RowBackColor");
    self.OddRowBackColor = (self.topDiv.getAttribute("OddRowBackColor") ? self.topDiv.getAttribute("OddRowBackColor") : "");

    self.CustomRowTip = self.topDiv.getAttribute("CustomRowTip");

    self.tipdiv = document.createElement("div");
    self.tipdiv.className = (self.topDiv.getAttribute("CustomRowTipCss") ? self.topDiv.getAttribute("CustomRowTipCss") : "def_tip_css");
    self.topDiv.appendChild(self.tipdiv);
    self.tipdiv.style.display = "none";
    
    self.onRowMouseOver = self.topDiv.getAttribute("onRowMouseOver");
    self.onRowMouseOut = self.topDiv.getAttribute("onRowMouseOut");

    self.PagerCss = (self.topDiv.getAttribute("PagerCss") ? self.topDiv.getAttribute("PagerCss") : "def_pager_css");
    self.SelPagerCss = (self.topDiv.getAttribute("SelPagerCss") ? self.topDiv.getAttribute("SelPagerCss") : "def_selpager_css");
    self.PagerSepCss = (self.topDiv.getAttribute("PagerSepCss") ? self.topDiv.getAttribute("PagerSepCss") : "def_pagersep_css");
    self.TopPagerCss = (self.topDiv.getAttribute("TopPagerCss") ? self.topDiv.getAttribute("TopPagerCss") : "def_toppager_css");
    self.BotPagerCss = (self.topDiv.getAttribute("BotPagerCss") ? self.topDiv.getAttribute("BotPagerCss") : "def_botpager_css");

    self.TextAreaCss = (self.topDiv.getAttribute("TextAreaCss") ? self.topDiv.getAttribute("TextAreaCss") : "def_textarea_css");

    self.ReadonlyBy  = self.topDiv.getAttribute("ReadonlyBy");
    self.ReadonlyCss = (self.topDiv.getAttribute("ReadonlyCss") ? self.topDiv.getAttribute("ReadonlyCss") : "def_readonly_cell_css");

    self.multSel = !eq(self.topDiv.getAttribute("multSel"), "False");

    self.InsertRowOnTab = eq(self.topDiv.getAttribute("InsertRowOnTab"), "True");

    self.pdCached = eq(self.topDiv.getAttribute("pdCached"), "True");
    
    self.HtmBlocks = eq(self.topDiv.getAttribute("HtmBlocks"), "True");        
    
    self.SortNames = (self.topDiv.getAttribute("SortNames") ? self.topDiv.getAttribute("SortNames") : "");
    var t = document.createElement("TABLE");
    self.rowPattern = t.insertRow(-1);
    self.rowPattern.className = self.RowCss;

    for(var k = 0; k < self.headRow.cells.length; k++)
    {
        var r = self.headRow;
        self.rowPattern.insertCell(-1).setAttribute("columnIndex", k);
        r.cells[k].setAttribute("columnIndex", k);
        self.colDefs[k] = new Object();
        self.colDefs[k].cnIndex        = k;
        self.colDefs[k].cnTitle        = r.cells[k].innerHTML;
        self.colDefs[k].cnTip          = r.cells[k].getAttribute("cnTip");
        self.colDefs[k].cnCstmTip      = r.cells[k].getAttribute("cnCstmTip");
        self.colDefs[k].cnWordWrap     = eq(r.cells[k].getAttribute("cnWordWrap"),"True");
        self.colDefs[k].cnSorting      = eq(r.cells[k].getAttribute("cnSorting"),"True");
        self.colDefs[k].cnReverseSorting = eq(r.cells[k].getAttribute("cnReverseSorting"),"True");
        self.colDefs[k].cnTitleCss     = r.cells[k].getAttribute("cnTitleCss");
        self.colDefs[k].cnEditType     = fldType(r.cells[k].getAttribute("cnEditType"));
        self.colDefs[k].cnCellCss      = r.cells[k].getAttribute("cnCellCss");
        self.colDefs[k].cnDefVal       = r.cells[k].getAttribute("cnDefVal");
        self.colDefs[k].cnDBName       = r.cells[k].getAttribute("cnDBName");
        self.colDefs[k].cnMaxLen       = r.cells[k].getAttribute("cnMaxLen");
        self.colDefs[k].cnValidate     = r.cells[k].getAttribute("cnValidate");
        self.colDefs[k].cnFormat       = r.cells[k].getAttribute("cnFormat");
        self.colDefs[k].cnImpCss       = r.cells[k].getAttribute("cnImpCss");
        self.colDefs[k].cnRelTableName = r.cells[k].getAttribute("cnRelTableName");
        self.colDefs[k].cnCached       = eq(r.cells[k].getAttribute("cnCached"),"True");
        self.colDefs[k].cnDepend       = r.cells[k].getAttribute("cnDepend");
        self.colDefs[k].cnRelBackColor = r.cells[k].getAttribute("cnRelBackColor");
        self.colDefs[k].cnRelShowInPD  = r.cells[k].getAttribute("cnRelShowInPD");
        self.colDefs[k].cnPdNullValue  = (r.cells[k].getAttribute("cnPdNullValue") != null ? r.cells[k].getAttribute("cnPdNullValue") : "-1");
        self.colDefs[k].cnBackColor    = r.cells[k].getAttribute("cnBackColor");
        self.colDefs[k].cnCellTemplFnc = r.cells[k].getAttribute("cnCellTemplateFunction");
        self.colDefs[k].cnCellTemplIH  = r.cells[k].innerHTML;
        self.colDefs[k].cnReadonly     = eq(r.cells[k].getAttribute("cnReadonly"),"True");
        self.colDefs[k].cnButtons      = eq(r.cells[k].getAttribute("cnButtons"),"True");
        self.colDefs[k].cnReadonlyBy   = r.cells[k].getAttribute("cnReadonlyBy");
        self.colDefs[k].cnRelNamesStr  = r.cells[k].getAttribute("cnRelNames");
        self.colDefs[k].cnRelValuesStr = r.cells[k].getAttribute("cnRelValues");
        self.colDefs[k].cnRelColorsStr = r.cells[k].getAttribute("cnRelColors");
        self.colDefs[k].cnRelSplitter  = (r.cells[k].getAttribute("cnRelSplitter") ? r.cells[k].getAttribute("cnRelSplitter") : ",");
        self.colDefs[k].cnCustomValue  = r.cells[k].getAttribute("cnCustomValue");
        self.colDefs[k].cnInEditForm   = !eq(r.cells[k].getAttribute("InEditForm"), "False");
        self.colDefs[k].cnPopUpCptn    = r.cells[k].getAttribute("cnPopUpCptn");
        self.colDefs[k].RefreshTableOnChange = eq(r.cells[k].getAttribute("RefreshTableOnChange"), "True");
        self.colDefs[k].RefreshFieldOnChange = r.cells[k].getAttribute("RefreshFieldOnChange");
        //------------------------------- special Auto Complete attributes -----------------------------------//
        // standart attributes will be used by Auto Complete: cnRelTableName, cnRelNames, cnRelColors, cnRelBackColor
        self.colDefs[k].cnMaxOpts = r.cells[k].getAttribute("cnMaxOpts");
        self.colDefs[k].cnColumn  = r.cells[k].getAttribute("cnColumn");
        self.colDefs[k].cnVColumn = r.cells[k].getAttribute("cnVColumn");
        self.colDefs[k].cnFilter  = r.cells[k].getAttribute("cnFilter");
        self.colDefs[k].divW      = r.cells[k].getAttribute("divW");
        self.colDefs[k].divH      = r.cells[k].getAttribute("divH");
        //----------------------------------------------------------------------------------------------------//
        self.colDefs[k].cnRelNames    = null;
        self.colDefs[k].cnRelValues   = null;
        self.colDefs[k].cnRelColors   = null;
        self.colDefs[k].cnShowInPD    = null;
        self.colDefs[k].cnSpellCheck  = eq(r.cells[k].getAttribute("spellcheck"), "True");
        self.colDefs[k].cnNoGrammarCheck = eq(r.cells[k].getAttribute("nogrammarcheck"), "True");
        if (self.colDefs[k].cnEditType == fType.Delete && self.colDefs[k].cnCellCss == null) 
        {
            self.colDefs[k].cnCellCss = "def_delcolumn_css";
            r.cells[k].className = self.colDefs[k].cnCellCss;
        }
        if(self.colDefs[k].cnTitleCss) r.cells[k].className = self.colDefs[k].cnTitleCss;
        self.colDefs[k].cnSortDr = "";
        self.colDefs[k].cnValues = new Object();
        self.colDefs[k].cnKeys = new Object();
    }

    self.PopUpInsert = eq(self.topDiv.getAttribute("PopUpInsert"), "True");
    self.PopUpInsertBtn = !eq(self.topDiv.getAttribute("PopUpInsertBtn"), "False");
    
    if(self.PopUpInsert)
    {
        self.popupdiv = document.createElement("div");
        self.topDiv.appendChild(self.popupdiv);
        self.PopUpInsertCaption = (self.topDiv.getAttribute("PopUpInsertCaption") ? self.topDiv.getAttribute("PopUpInsertCaption") : "Create new entry");
        var PopUpInsertCaptionStr = " Caption3d='" + self.PopUpInsertCaption + "'";
        var PopUpInsertCss = " style='" + (self.topDiv.getAttribute("PopUpInsertStyle") ? self.topDiv.getAttribute("PopUpInsertStyle") : "") + "'";
        var PopUpInsertClass = " class='" + (self.topDiv.getAttribute("PopUpInsertCss") ? self.topDiv.getAttribute("PopUpInsertClass") : "") + "'";
        
        self.popupdiv.innerHTML = "<div id='" + self.name + "_Inner_PopUp' Style3d='True' OnHide=\"TableClearEF('" + self.name + "');\" " + PopUpInsertCaptionStr + PopUpInsertCss + PopUpInsertClass + ">" +
            "<table style='width:100%; height:100%;'><tr><td id='" + self.name + "_EditFormHolder'></td></tr>" +
                "<tr><td align='center' style='padding-top:20px;'>" +
                    "<input type='button' value='Create' onclick=\"TableMakeInsertEF('" + self.name + "');\"  />" +
                    "<input type='button' value='Cancel' onclick=\"PopUpShow('" + self.name + "_Inner', false);\"  />" +
                "</td></tr></table></div>";

        PopUpInit(self.name + "_Inner");
    }

    
    self.RefreshBtn = eq(self.topDiv.getAttribute("RefreshBtn"), "True");
    self.RefreshImg = (self.topDiv.getAttribute("RefreshImg") ? self.topDiv.getAttribute("RefreshImg") : patImg_Refresh);
    self.RefreshCaption = (self.topDiv.getAttribute("RefreshCaption") ? self.topDiv.getAttribute("RefreshCaption") : "Refresh");
    
    self.HideRowsBtn = eq(self.topDiv.getAttribute("HideRowsBtn"), "True");
    self.HideRowsImg = (self.topDiv.getAttribute("HideRowsImg") ? self.topDiv.getAttribute("HideRowsImg") : patImg_HideRows);
    self.HideRowsCpt = (self.topDiv.getAttribute("HideRowsCpt") ? self.topDiv.getAttribute("HideRowsCpt") : "Hide rows");
    self.ShowRowsImg = (self.topDiv.getAttribute("ShowRowsImg") ? self.topDiv.getAttribute("ShowRowsImg") : patImg_ShowRows);
    self.ShowRowsCpt = (self.topDiv.getAttribute("ShowRowsCpt") ? self.topDiv.getAttribute("ShowRowsCpt") : "Show rows");
    
    self.HideRowsOnSelect = eq(self.topDiv.getAttribute("HideRowsOnSelect"), "True");
    
    self.InsertImg = (self.topDiv.getAttribute("InsertImg") ? self.topDiv.getAttribute("InsertImg") : patImg_Add);
    self.insRow = null;
    self.insRowDef = null;

    if(!eq(self.topDiv.getAttribute("InsertRow"), "False") && !self.PopUpInsert || eq(self.topDiv.getAttribute("InsertRow"), "True"))
    {
        self.insRow = document.createElement("tr");
        self.insRow.dbid = "-1";
        self.insRow.className = self.RowCss;
        for (var j = 0; j < self.colDefs.length; j++) 
        {
            var cell = document.createElement("td");
            self.insRow.appendChild(cell);
            cell.setAttribute("columnIndex", j);
            if(self.colDefs[j].cnEditType == fType.Delete)
                cell.innerHTML = "<img style='border:0' title='Insert Row' alt='Insert Row' src='" + self.InsertImg + "' onclick=\"if(this.getAttribute('disabled') != 'disabled'){ TableMakeInsert('" + self.name + "'); event.cancelBubble = true;}\" />";
        }
    }
    
    self.EditFormInput = function (coldef)
    {
        var theEditor;
        switch(coldef.cnEditType)
        {
            case fType.Text:
                theEditor = document.createElement("INPUT");
                theEditor.type = "text";

                if(coldef.cnRelTableName) 
                {
                    theEditor.setAttribute("autocomplete","off");

                    theEditor.setAttribute("cnRelTableName", coldef.cnRelTableName);
                    if(coldef.cnRelColors)    theEditor.setAttribute("cnRelColors",    coldef.cnRelColors);
                    if(coldef.cnRelNames)     theEditor.setAttribute("cnRelNames",     coldef.cnRelNames);
                    if(coldef.cnRelBackColor) theEditor.setAttribute("cnRelBackColor", coldef.cnRelBackColor);
                    if(coldef.cnMaxOpts)      theEditor.setAttribute("cnMaxOpts",      coldef.cnMaxOpts);
                    if(coldef.cnColumn)       theEditor.setAttribute("cnColumn",       coldef.cnColumn);
                    if(coldef.cnVColumn)      theEditor.setAttribute("cnVColumn",      coldef.cnVColumn);
                    if(coldef.cnFilter)       theEditor.setAttribute("cnFilter",       coldef.cnFilter);
                    if(coldef.divW)           theEditor.setAttribute("divW",           coldef.divW);
                    if(coldef.divH)           theEditor.setAttribute("divH",           coldef.divH);

                    theEditor.setAttribute("onHide", "TableEndEdit('" + self.name + "')");
                    
                    window.setTimeout(function(){if(theEditor)AutoCompleteInit(theEditor.id);}, 5);
                }

                break;
            case fType.Money:
                theEditor = document.createElement("INPUT");
                theEditor.type = "text";
                theEditor.onkeydown = function(evt){return ImpEventMoneyFormatCheck(this, (evt ? evt : window.event)); };
                break;
            case fType.Textarea:
            case fType.Html:
                theEditor = document.createElement("textarea");
                theEditor.className = (self.topDiv.getAttribute("EditformTaCss") ? self.topDiv.getAttribute("EditformTaCss") : "def_editform_ta_css");;
                break;
            case fType.Datetime:
                theEditor = document.createElement("INPUT");
                theEditor.type = "text";

                /*
	            if(coldef.cnClndBtn != "False")
	            {
	                theEditor.style.height = "12px";
    		        
                    var bt = document.createElement("img");    
                    bt.id = theEditor.id + "_CalendarBtn";
                    bt.setAttribute("impId", theEditor.id);
                    bt.alt = "";
                    bt.src = "PAT/Calendar/calendar.gif";

                    var pr = theEditor.parentNode;
                    var t = document.createElement("table");  
                    t.className = "def_emptytable_css"; 
                    var r = t.insertRow(0);
                    r.insertCell(0).appendChild(theEditor);
                    r.insertCell(1).appendChild(bt);

                    pr.appendChild(t);
                    bt.onclick = function(){if(!$get(this.getAttribute("impId")).disabled) return popUpCalendar(this, $get(this.getAttribute("impId")), 'MM/dd/yyyy'); };
                    theEditor.onclick = function(){if(!this.disabled) return popUpCalendar($get(this.id + "_CalendarBtn"), this, 'MM/dd/yyyy'); };
                }
                else
                */
                    theEditor.onclick = function(){if(!this.disabled) return popUpCalendar(this, this, 'MM/dd/yyyy'); };

                break;
            case fType.Select:
                theEditor = document.createElement("SELECT");

                break;
            case fType.Check:
	            theEditor = document.createElement("INPUT");
	            theEditor.type = "checkbox";
                break;
        }

        theEditor.id = self.name + "_editform_" + coldef.cnIndex;
        return theEditor;
    }
    
    self.EditFormHolder = $get(self.name + "_EditFormHolder");
    if(self.EditFormHolder)
    {
        self.EditForm = document.createElement("div");
        for (var j = 0; j < self.colDefs.length; j++) 
        {
            var coldef = self.colDefs[j];
            if(coldef.cnEditType == fType.Delete || coldef.cnEditType == fType.Multsel || coldef.cnEditType == fType.Custom || coldef.cnEditType == fType.None || !coldef.cnInEditForm || coldef.cnReadonly) continue;

            var theEditor = self.EditFormInput(coldef);
            coldef.cnEditFormInput = theEditor;

            var elDiv = document.createElement("div");
            elDiv.className = (self.topDiv.getAttribute("EditformElCss") ? self.topDiv.getAttribute("EditformElCss") : "def_editform_el_css");
            if(coldef.cnEditType == fType.Textarea) elDiv.className = (self.topDiv.getAttribute("EditformElTaCss") ? self.topDiv.getAttribute("EditformElTaCss") : "def_editform_elta_css");
            
            self.EditForm.appendChild(elDiv);

            var nameDiv = document.createElement("div");
            nameDiv.className = (self.topDiv.getAttribute("EditformNameCss") ? self.topDiv.getAttribute("EditformNameCss") : "def_editform_name_css");
            nameDiv.innerHTML = (coldef.cnPopUpCptn != null && coldef.cnPopUpCptn != "") ? coldef.cnPopUpCptn : coldef.cnTitle;
            elDiv.appendChild(nameDiv);
            
            var valDiv = document.createElement("div");
            valDiv.className = (self.topDiv.getAttribute("EditformValCss") ? self.topDiv.getAttribute("EditformValCss") : "def_editform_val_css");
            valDiv.appendChild(theEditor);
            elDiv.appendChild(valDiv);
        }
        self.EditFormHolder.appendChild(self.EditForm);
    }

    self.ClearEF = function ()
    {
        for (var j = 0; j < self.colDefs.length; j++) 
            if(self.colDefs[j].cnEditFormInput) 
                ClearInput(self.colDefs[j].cnEditFormInput);
    }

    self.ShowEF = function (show)
    {
        show = (show == null ? true : show);
        PopUpShow(self.name + "_Inner", show);
    }
    
    self.DeleteImg = (self.topDiv.getAttribute("DeleteImg") ? self.topDiv.getAttribute("DeleteImg") : patImg_Cancel);
    self.DeleteGrayImg = (self.topDiv.getAttribute("DeleteGrayImg") ? self.topDiv.getAttribute("DeleteGrayImg") : patImg_CancelD);

    self.GetCurrentRowID = function ()
        {
            var id = null;
            if (self.curRow != null)
                id = self.curRow.dbid;
            return id;
        }
        
    self.HideShowCol = function(index, hide) 
    {
        try {
            var col = self.rowPattern.cells[index];
            col.style.display = hide ? "" : "none";
            col = self.headRow.cells[index];
            col.style.display = hide ? "" : "none";
            for (var i = 0; i < self.tableHolders.length; i++) {
                var tab = self.tableHolders[i].getElementsByTagName("TABLE")[0];
                for (var i = 0; i < tab.rows.length; i++) {
                    col = tab.rows[i].cells[index];
                    col.style.display = hide ? "" : "none";
                }
            }
        } catch (e) { OnErr({obj: self, msg: "Can't hide column", val: index}); }
    }

    self.HideRows = function(hide, exeptCur, exeptSel)
    {
        for (var i = 0; i < self.TableRows.length; i++)
            if(!exeptCur || self.TableRows[i] != self.curRow && !exeptSel || !self.isSelected(self.TableRows[i]))
                self.TableRows[i].style.display = hide ? "none" : "";
        if(!exeptCur || self.insRow != self.curRow && exeptSel || self.isSelected(self.insRow))
            if(self.insRow) self.insRow.style.display = hide ? "none" : "";
            
        if(self.hrBtn) self.hrBtn.style.display = hide ? "none" : "";
        if(self.srBtn) self.srBtn.style.display = hide ? "" : "none";
            
        if(self.topPager) self.topPager.style.display = hide ? "none" : "";
        if(self.botPager) self.botPager.style.display = hide ? "none" : "";
        disableCtrl(self.rowsPP, hide);
        disableCtrl(self.gotoPage, hide);
    }

    self.HideRows_ = function()
    {
        self.HideRows(true, true, true);
    }

    self.ShowRows_ = function()
    {
        self.HideRows(false, true, true);
    }


    self.GetDataRow = function (rowID)
        {
            if (self && self.table && self.table.rows)
                for (var index =0; index < self.table.rows.length; index++)
                    if (self.table.rows[index][self.DbRowId] == rowID)
                        return self.table.rows[index];
            return null;
        }

    self.GetDataValue = function (columnName, rowID)
        {
            var row = self.GetDataRow(rowID);
            if(row) return row[columnName];
            return null;
        }
    self.GetCurRowValueByColumn = function (columnName)
        {
            if(self.curRow) 
                return self.GetDataValue(columnName, self.curRow.dbid);
            return null;
        }

    self.OnDataChangeNotification = function (params) 
        { 
            if(params != null && eq(params["act"],"sre_setdata") && params["rowId"] != null)
                self.RefreshRow(params["rowId"])
            else
                self.LoadData();
        }

    self.OnRowChangeNotification = function (params) 
        { 
            if(params != null && params["rowId"] != null && params["rowidname"] != null)
                self.args = AddHash(self.args, params["rowidname"], params["rowId"]);
		    self.currentPage = 1;
			self.LoadData();
        }

    self.OnServiceRes = function (res)
        {
            switch(res["cmdCode"].toUpperCase()) 
            {
                case "GETSINGLEROW": self.OnGetSingleRowRes(res); break;
                case "GETPAGE":      self.OnGetPageRes(res); break;
                case "GETPDTABLE":   self.OnGetPDTableRes(res); break;
                case "DELROW":       self.OnDelRowRes(res); break;
                case "SETDATA":      self.OnSetDataRes(res); break;
                case "INSROW":       self.OnInsRowRes(res); break;
            }
        }

    self.Refresh = function (args) 
        { 
            //self.currentPage = 1;
            self.LoadData(args);
        }

    self.Refresh_ = function (obj, evt) 
        { 
            self.Refresh(null);
        }

    self.RefreshRow = function (rowId, fieldDbName) 
        { 
            ServerCall("GetSingleRow", self, {rowId: rowId, field: fieldDbName, args: self.args});
        }

    self.SetCurRow = function (rowId) 
        { 
            if(!rowId) return self.SelectRowByRow(null, null);
            
            var row = self.Row(rowId);
		    if(row) return self.SelectRowByRow(row, null);
            
            self.ClearAllSelection();
            ServerCall("GetPage", self, {rowId: rowId, pagesize: self.RowsCnt, sort: self.SortNames, args: self.args}); 
        }

    self.OnGetSingleRowRes = function(res) 
        {
            if (res["errCode"] != null) return OnErr({obj: self, msg: res["errCode"]});
            var tabData = res["tableRes"];
            var rowId = res["args"]["rowId"];
            var field = res["args"]["field"];

            if (tabData == null || tabData.rows == null || tabData.rows.length == 0) return;

            var newRow = self.DataRow(tabData, rowId);
            var oldRow = self.DataRow(self.table, rowId);
            if(newRow && oldRow)
    	        for (var clmn in newRow)
    		        oldRow[clmn] = newRow[clmn];

            var row = self.Row(rowId);
            for (var j = 0; j < self.colDefs.length; j++) {
                if(field != null && trim(field) != "" && self.colDefs[j].cnDBName != field) continue;
                self.setCell(row, self.colDefs[j], tabData.rows[0][self.colDefs[j].cnDBName], tabData.rows[0]);
                if (self.colDefs[j].cnEditType == fType.Select || self.colDefs[j].cnEditType == fType.DDEx) self.SetPullDownCell(row.cells[j], self.colDefs[j]);
            }
        }

    self.DataRow = function (datatable, id)
    {
        if(!datatable || !datatable.rows) return null;
        for (var i = 0; i < datatable.rows.length; i++)
	        if(datatable.rows[i][self.DbRowId] == id)
	            return datatable.rows[i];
        return null;
	}
    
    self.GetColdefByDbName = function (dbName) 
    {
        for (var i=0;i<self.colDefs.length;i++)
        {
            if(self.colDefs[i].cnDBName == dbName)
                return self.colDefs[i];
        }
        return null;
    }
    
    self.JsSort = function (sortStr) 
    {
        var names = sortStr.split(",");
        for (var i=0; i<names.length; i++)
        {
            var prts = trim(names[i]).split(" ");
            if(prts.length > 0)
                self.SetSortDirImg(self.GetColdefByDbName(prts[0]), prts.length == 2 ? prts[1] : "asc");
        }

        self.Sort(sortStr);
    }

    self.SetSortDirImg = function (coldef, sDr) // Dir: "asc" "desc" ""
    {
        if(coldef == null) return;
        coldef.cnSortDr = sDr;
        var img = coldef.headCell.childNodes[0].childNodes[0].childNodes[0].childNodes[1].childNodes[0];
        if(!eq(img.tagName, "img")) return;
        img.src = (sDr == "" ? patImg_UpDn : sDr == "asc" ? patImg_Dn : patImg_Up);
        img.alt = (sDr == "" ? "sort asc" : sDr == "asc" ? "sort desc" : "no sorting");
    }


    self.SortOnHeadClick = function (cell, evt) 
        {
            if(!eq(cell.tagName, "td")) return;
            
            var coldef = self.colDefs[cell.getAttribute("columnIndex")];
                        
            if(!self.MultiColumnsSorting)
            {
                for(var k = 0; k < cell.parentNode.cells.length; k++)
                {
                    if(!self.colDefs[k].cnSorting || cell.getAttribute("columnIndex") == k || cell.parentNode.cells[k].childNodes.length == 0 || cell.parentNode.cells[k].childNodes[0].nodeName == "#text" || self.colDefs[k].cnEditType == fType.Delete || self.colDefs[k].cnButtons) continue;
                    var img = cell.parentNode.cells[k].childNodes[0].childNodes[0].childNodes[0].childNodes[1].childNodes[0];
                    if(eq(img.tagName, "img"))
                    {
                        img.src = patImg_UpDn;
                        img.alt = "no sorting";
                        self.colDefs[k].cnSortDr = "";
                    }
                }
            }

            var sDr = "";
            if (coldef.cnReverseSorting)
            {
                sDr = (coldef.cnSortDr == "" ? "desc" : coldef.cnSortDr == "desc" ? "asc" : "");
            }
            else
            {
                sDr = (coldef.cnSortDr == "" ? "asc" : coldef.cnSortDr == "asc" ? "desc" : "");
            }
            
            coldef.cnSortDr = sDr;
            var img = cell.childNodes[0].childNodes[0].childNodes[0].childNodes[1].childNodes[0];
            if(!eq(img.tagName, "img")) return;
            img.src = (sDr == "" ? patImg_UpDn : sDr == "asc" ? patImg_Dn : patImg_Up);
            img.alt = (sDr == "" ? "sort asc" : sDr == "asc" ? "sort desc" : "no sorting");
            
            
            if(self.MultiColumnsSorting)
            {
                var sNames = (self.SortNames != null ? self.SortNames.split(",") : new Array());
                self.SortNames = "";
                for(var i=0; i<sNames.length; i++)
                    if(sNames[i].substring(0,coldef.cnDBName.length) != coldef.cnDBName)
                        self.SortNames += (self.SortNames == "" ? "" : ",") + sNames[i];
            }
            else
                self.SortNames = "";
    
            self.SortNames += (sDr != "" ? (self.SortNames == "" ? "" : ",") + coldef.cnDBName + " " + sDr : "") ;

            self.Sort(self.SortNames);
        }
        
    self.Sort = function (sNames) 
    {
        self.SortNames = sNames;
        self.LoadData(); 
    }

    self.LoadData = function (args) 
        {
            if(args) AddHash(self.args, args);
            ServerCall("GetPage", self, {page: self.currentPage, pagesize: self.RowsCnt, sort: self.SortNames, args: self.args});
        }

    self.OnGetPageRes = function (res) 
        {
            if (res["errCode"] != null) return OnErr({obj: self, msg: res["errCode"]});
            var tabData = res["tableRes"];
            self.table = tabData;
            self.rowsTotal = res["scalarRes"];
            self.pagesCount = (self.RowsCnt == null || self.RowsCnt == 0 ? 1 : 1 + parseInt((self.rowsTotal - 1) / self.RowsCnt));
            if(self.pagesCount < 1) self.pagesCount = 1;
            if(self.currentPage > self.pagesCount) TableSetCurPage(self.name, self.pagesCount);

            if(self.HtmBlocks)
            {
                if(self.BlocksHolder == null) 
                {
                    self.BlocksHolder = document.createElement("div");
                    self.topDiv.insertBefore(self.BlocksHolder, self.tabPattern);
                }
                self.BlocksHolder.innerHTML = "";

                if(tabData == null || tabData.rows == null) return;
                for (var i = 0; i < tabData.rows.length; i++)
                    for (var j = 0; j < self.colDefs.length; j++)
                        self.BlocksHolder.innerHTML += tabData.rows[i][self.colDefs[j].cnDBName];
                        
                return;
            }

            var curRowId, curRowRestored = false;
            if (self.curRow != null)
            {
                curRowId = self.curRow.dbid;
                self.UnselectCurRow(true);
            }
            if(res["args"]["rowId"] != null) 
            {
                curRowId = res["args"]["rowId"];
                ExecEx(self, "onSelRow", {obj: self, curRowId: curRowId});
            }

            self.currentPage = (res["args"]["page"] == null ? 1 : res["args"]["page"]);

            var len = (tabData != null && tabData.rows != null ? tabData.rows.length : 0);
            for(var i=0; i<len; i++)
                if(tabData.rows[i][self.DbRowId] == "-1")
                {
                    self.insRowDef = tabData.rows[i];
                    Array.removeAt(tabData.rows,i);
                    len--;
                }
            
            if(self.MaxRows != null && self.insRow != null)
                self.insRow.style.display= (self.MaxRows <= len ? "none" : "");

            self.SizeTable(len);

            for (var i=0;i<self.colDefs.length;i++)
            {
                var cd = self.colDefs[i];
                var val = cd.cnDefVal == null ? "" : cd.cnDefVal;
                if(self.insRowDef != null) val = self.insRowDef[cd.cnDBName] == null ? val : self.insRowDef[cd.cnDBName];
                if(self.insRow) self.setCell(self.insRow, cd, val, self.insRowDef);
                if(cd.cnEditFormInput) cd.cnEditFormInput.value = self.FormatValue(val, cd);
                if(self.insRow && (cd.cnEditType == fType.Select || cd.cnEditType == fType.DDEx)) self.SetPullDownCell( self.insRow.cells[i], cd);
            }    
                   
            if(self.insRow)                       
            {
                AddHandler(self.insRow, "click", self.SelectRowByRow);
                AddHandler(self.insRow, "mouseover", self.rowMouseOver);
                AddHandler(self.insRow, "mouseout", self.rowMouseOut);
            }

            for (var i = 0; i < len; i++)
            {
                var row = self.TableRows[i];
                row.dbid = tabData.rows[i][self.DbRowId];
                                
                AddHandler(row, "click", self.SelectRowByRow);
                AddHandler(row, "mouseover", self.rowMouseOver);
                AddHandler(row, "mouseout", self.rowMouseOut);

                for (var j = 0; j < self.colDefs.length; j++)
                    self.setCell(row, self.colDefs[j], tabData.rows[i][self.colDefs[j].cnDBName], tabData.rows[i]);
                
                if (curRowId && row.dbid == curRowId) { self.SelectCurRow(row); curRowRestored = true; }
                self.SelectRow(row.dbid,self.selRowsId[row.dbid]);
                if(self.OddRowBackColor && i%2==0) row.style.backgroundColor = self.OddRowBackColor;
            }
            
            if(curRowId != null && curRowId != "")
                if(!curRowRestored)
                {
                    ExecEx(self, "onSelRow", {obj: self, curRowId: "-1"});
                    RowChangeNotify(self.RowChangeNotifyList, {rowId: "-1", rowidname: self.DbRowId});
                    ExecEx(self, "onRowSelected", {obj: self, curRowId: "-1"});
                }
                else if(res["args"]["rowId"] != null) // row was setted
                {
                    ExecEx(self, "onSelRow", {obj: self, curRowId: curRowId});
                    RowChangeNotify(self.RowChangeNotifyList, {rowId: curRowId, rowidname: self.DbRowId});
                    ExecEx(self, "onRowSelected", {obj: self, curRowId: curRowId});
                }
                
            for (var i = 0; i < self.colDefs.length; i++)
            {
                var cd = self.colDefs[i];
                if(cd.cnEditType != fType.Select && cd.cnEditType != fType.DDEx) continue;
                if((self.pdCached || cd.cnCached) && cd.cnDataLoaded) {self.SetPDData(cd); continue;}
                if (cd.cnRelTableName != null)
                    ServerCall("GetPDTable", self, {pdName: cd.cnRelTableName, args: self.args, columnIndex: i});
                else
                    self.OnGetPDTableRes({args: {pdName: null, columnIndex: i}});
            }
            
            if(self.LockedBody) self.LockTable(self.LockedBody, self.LockedInsR);
            if(res.args.args.SelectFirstInsCell == 1) 
            {
                self.selectCell(self.getNextEditCellInRow(self.insRow, 0), self.insRow);
                delete res.args.args.SelectFirstInsCell;
            }
            ExecEx(self, "onRowSelected", {obj: self, curRowId: (self.curRow ? "" + self.curRow.dbid : "")});
        }


        self.OnGetPDTableRes = function(res) {
            if (res["errCode"] != null) return OnErr({obj: self, msg: res["errCode"]});
            var columnIndex = res["args"]["columnIndex"];
            var pdName = res["args"]["pdName"];
            var cd = self.colDefs[columnIndex];
            cd.dataRes = res["tableRes"];

            if(cd.cnRelNames) delete cd.cnRelNames;
            if(cd.cnRelValues) delete cd.cnRelValues;
            if(cd.cnRelColors) delete cd.cnRelColors;
            if(cd.cnShowInPD) delete cd.cnShowInPD;
            if(cd.cnDataRow) delete cd.cnDataRow;
            cd.cnRelNames = (cd.cnRelNamesStr != null ? cd.cnRelNamesStr.split(cd.cnRelSplitter) : new Array());
            cd.cnRelValues = (cd.cnRelValuesStr != null ? cd.cnRelValuesStr.split(cd.cnRelSplitter) : new Array());
            cd.cnRelColors = (cd.cnRelColorsStr != null ? cd.cnRelColorsStr.split(cd.cnRelSplitter) : new Array());
            cd.cnShowInPD = new Array();
            cd.cnDataRow = new Array();
            if (cd.dataRes && cd.dataRes.rows && cd.dataRes.rows.length) {
                for (var i = 0; i < cd.dataRes.rows.length; i++) {
                    var len = cd.cnRelNames.length != null ? cd.cnRelNames.length : 0;
                    cd.cnRelNames[len] = cd.dataRes.rows[i][cd.dataRes.columns[1].name];
                    cd.cnRelValues[len] = cd.dataRes.rows[i][cd.dataRes.columns[0].name];
                    cd.cnDataRow[len] = cd.dataRes.rows[i];
                    if (cd.cnRelBackColor != null) cd.cnRelColors[len] = cd.dataRes.rows[i][cd.cnRelBackColor];
                    if (cd.cnRelShowInPD != null) cd.cnShowInPD[len] = cd.dataRes.rows[i][cd.cnRelShowInPD];
                }
            }
            cd.cnDataLoaded = true;
            self.SetPDData(cd);
        }

        self.SetPDData = function(coldef) {
            if (self.insRow) self.SetPullDownCell(self.insRow.cells[coldef.cnIndex], coldef);
            if (coldef.cnEditFormInput) 
            {
                self.SetPullDownOptions(coldef, coldef.cnEditFormInput, null);
                if(self.insRowDef)coldef.cnEditFormInput.value = self.insRowDef[coldef.cnDBName];
            }
            for (var i = 0; i < self.TableRows.length; i++)
                self.SetPullDownCell(self.TableRows[i].cells[coldef.cnIndex], coldef);
        }

        self.SetPullDownOptions = function(coldef, theEditor, row) 
        {
            if(coldef.cnRelNames != null && coldef.cnRelNames.length != null && coldef.cnRelValues != null && coldef.cnRelValues.length == coldef.cnRelNames.length)
                theEditor.innerHTML = "";
                for (var i=0; i < coldef.cnRelNames.length; i++)
                {
                    if(coldef.cnShowInPD != null && coldef.cnShowInPD.length == coldef.cnRelNames.length && !coldef.cnShowInPD[i] && (row == null || coldef.cnValues[row.dbid] != coldef.cnRelValues[i]))
                            continue;
                    if(row != null && !self.CheckKeys(row.dbid, i, coldef)) continue;
                    var el = new Option(coldef.cnRelNames[i], coldef.cnRelValues[i]);
                    theEditor.options.add(el);
                    if (coldef.cnRelColors != null && coldef.cnRelColors.length == coldef.cnRelNames.length)
                            el.style.backgroundColor = coldef.cnRelColors[i];
                }
        }

        self.CheckKeys = function(rowid, datarownum, coldef) {
            if(coldef.cnKeys != null && coldef.cnKeys[rowid] != null)
                for (var prop in coldef.cnKeys[rowid])
                    if(coldef.cnDataRow[datarownum][prop] != null && coldef.cnDataRow[datarownum][prop] != coldef.cnKeys[rowid][prop])
                        return false;
            return true;
        }
        
        self.LoadDepends = function(row, coldef)
        {
            if(coldef.cnDepend != null && coldef.cnDepend != "")
                for (var i = 0; i < self.colDefs.length; i++)
                {
                    var cd = self.colDefs[i];
                    if(cd.cnDBName != coldef.cnDepend) continue;
                    if(cd.cnKeys[row.dbid] == null) cd.cnKeys[row.dbid] = new Object();
                    cd.cnKeys[row.dbid][coldef.cnDBName] = coldef.cnValues[row.dbid];
                    self.SetPullDownCell(row.cells[cd.cnIndex], cd);
                }
        }

        self.SetPullDownCell = function(cell, coldef) {
            var val = null; 
            try{val = coldef.cnValues[cell.parentNode.dbid];}catch(err){OnErr({obj: self, msg: "Can't set value"});};
            if (coldef.cnRelNames != null && coldef.cnRelNames.length != null && coldef.cnRelValues != null && coldef.cnRelValues.length == coldef.cnRelNames.length)
                for (var i = 0; i < coldef.cnRelNames.length; i++)
                {
                    if (coldef.cnRelValues[i] == val || (coldef.cnRelValues[i] == null && val == "null") || (coldef.cnRelValues[i] == coldef.cnPdNullValue && val == null)) 
                    {
                        if(!self.CheckKeys(cell.parentNode.dbid, i, coldef)) continue;
                        cell.innerHTML = "<div class='def_valuediv_css " + (eq(cell.getAttribute("pat_readonlyObj"),"True") ? self.ReadonlyCss : "") + "' onselectstart='return false;'>" + self.FormatValue(coldef.cnRelNames[i], coldef) + "</div>";
                        if(self.theEditor) self.theEditor = null;
                        if (coldef.cnRelColors != null) {
                            cell.style.backgroundColor = coldef.cnRelColors[i];
                            cell.style.color = self.CalcTxtColor(coldef.cnRelColors[i]);
                        }
                        if(cell.firstChild && cell.firstChild.tagName && eq(cell.firstChild.tagName, "DIV"))
                        {
                            cell.firstChild.style.width = self.headRow.cells[coldef.cnIndex].style.width;
                            cell.firstChild.style.textAlign = self.headRow.cells[coldef.cnIndex].style.textAlign;
                            cell.firstChild.style.verticalAlign = "middle";
                        }
                        return;
                    }
                }
            cell.innerHTML = "<div></div>"
        }

        self.SizeTable = function(datarows) {
            var row, cell;
            while (self.TableRows.length > datarows)  //TODO
            {
                var r = self.TableRows.pop();
                var p = r.parentNode;
                p.removeChild(r);
                if (p.childNodes.length == (self.insRow == null ? 1 : 2)) p.parentNode.parentNode.removeChild(p.parentNode);
            }

            var insrowRendered = false;
            while (self.TableRows.length < datarows || datarows == 0) //TODO
            {
                var body;
                if ((self.PageSize == null && self.TableRows.length == 0) || self.TableRows.length % self.PageSize == 0) {
                    var page = (self.PageSize == null ? 0 : Math.round((self.TableRows.length - 1) / self.PageSize));
                    var t = self.tabPattern.cloneNode(false);
                    t.id = t.id + "_" + page;
                    t.style.display = "";
                    body = document.createElement("TBODY");
                    t.appendChild(body);
                    var head = self.headRow.cloneNode(true);
                    head.id = head.id + "_" + page;
                    body.appendChild(head); 
                    
                    for (var k = 0; k < head.cells.length; k++)
                    {
                        if(self.colDefs[k].cnEditType == fType.Delete || self.colDefs[k].cnButtons)
                        {
                            var btnstable = document.createElement("table");
                            btnstable.className = "def_sorttable_css";
                            var btnrow = btnstable.insertRow(0);
                            head.cells[k].appendChild(btnstable);
                            if(self.HideRowsBtn)
                            {
                                var btncell = btnrow.insertCell(0);
                                
                                self.hrBtn = document.createElement("img");
                                self.hrBtn.setAttribute("src", self.HideRowsImg);
                                self.hrBtn.setAttribute("alt", self.HideRowsCpt);
                                self.hrBtn.setAttribute("title", self.HideRowsCpt);
                                btncell.appendChild(self.hrBtn);
                                self.hrBtn.style.cursor = "pointer";
                                AddHandler(self.hrBtn, "click", self.HideRows_);

                                self.srBtn = document.createElement("img");
                                self.srBtn.setAttribute("src", self.ShowRowsImg);
                                self.srBtn.setAttribute("alt", self.ShowRowsCpt);
                                self.srBtn.setAttribute("title", self.ShowRowsCpt);
                                self.srBtn.style.display = "none";
                                btncell.appendChild(self.srBtn);
                                self.srBtn.style.cursor = "pointer";
                                AddHandler(self.srBtn, "click", self.ShowRows_);
                            }
                            if(self.RefreshBtn)
                            {
                                var img = document.createElement("img");
                                img.setAttribute("src", self.RefreshImg);
                                img.setAttribute("alt", self.RefreshCaption);
                                img.setAttribute("title", self.RefreshCaption);
                                btnrow.insertCell(0).appendChild(img);
                                img.style.cursor = "pointer";
                                AddHandler(img, "click", self.Refresh_);
                            }
                            if(self.PopUpInsert && self.PopUpInsertBtn)
                            {
                                var img = document.createElement("img");
                                img.setAttribute("src", self.InsertImg);
                                img.setAttribute("alt", self.PopUpInsertCaption);
                                img.setAttribute("title", self.PopUpInsertCaption);
                                btnrow.insertCell(0).appendChild(img);
                                img.style.cursor = "pointer";
                                AddHandler(img, "click", self.ShowEF);
                            }
                        }
                        if (self.colDefs[k].cnSorting) 
                        {
                            AddHandler(head.cells[k], "click", self.SortOnHeadClick);
                            head.cells[k].innerHTML = "<table class='def_sorttable_css'><tr><td>" + head.cells[k].innerHTML + "</td><td><img src='" + patImg_UpDn + "' alt='sort' /></td></tr></table>";
                        }
                        self.colDefs[k].headCell = head.cells[k];
                    }

                    if (self.insRow != null && self.TableRows.length == 0 && !insrowRendered) 
                    {
                        insrowRendered = true;
                        body.appendChild(self.insRow);

                        if(self.insRowHolder)
                        {
                            self.insRowHolder.innerHTML = "";
                            self.insRowHolder.appendChild(t);
                            continue;
                         }
                    }

                    self.tableHolders[page].innerHTML = "";
                    self.tableHolders[page].appendChild(t);
                }
                else
                    body = self.TableRows[self.TableRows.length - 1].parentNode;

                if (datarows == 0) break;
                var row = self.rowPattern.cloneNode(true);
                body.appendChild(row);
                self.TableRows.push(row);
            }

            //  Add pager control
            if (self.topPager || self.botPager) {
                var pagerCode = self.RenderPager(1);
                if (self.topPager && self.TopPagerCss) self.topPager.className = self.TopPagerCss;
                if (self.botPager && self.BotPagerCss) self.botPager.className = self.BotPagerCss;
                if (self.topPager) { self.topPager.innerHTML = pagerCode; self.topPager.style.display = (pagerCode == "" ? "none" : ""); }
                if (self.botPager) { self.botPager.innerHTML = pagerCode; self.botPager.style.display = (pagerCode == "" ? "none" : ""); }
            }

            if (self.rowsPP) {
                var rpp_sbscr = (self.rowsPP.getAttribute("sbscr") ? self.rowsPP.getAttribute("sbscr") : "rows/pp: ");
                self.rowsPP.innerHTML = rpp_sbscr + "<input style=\"width:30px;height:13px;font-size:11px;\" type=\"text\" value=\"" + self.PageSize + "\" onblur=\"javascript:TableSetRowsPerPage('" + self.name + "', this.value);\" onkeypress=\"javascript:if((window.event || event).keyCode == ENTER_KEY_CODE){TableSetRowsPerPage('" + self.name + "', this.value); return false;}\" />";
                self.rowsPP.className = (self.topDiv.getAttribute("RowsPPCss") ? self.topDiv.getAttribute("RowsPPCss") : "def_rowspp_css");
            }

            if (self.gotoPage) {
                var gtp_sbscr = (self.gotoPage.getAttribute("sbscr") ? self.gotoPage.getAttribute("sbscr") : "go to: ");
                self.gotoPage.innerHTML = (self.pagesCount > 1 ? gtp_sbscr + "<input style=\"width:30px;height:13px;font-size:11px;\" type=\"text\" value=\"" + self.currentPage + "\" onkeypress=\"javascript:if((window.event || event).keyCode == ENTER_KEY_CODE){TableSetCurPage('" + self.name + "', this.value); return false;}\" onblur=\"javascript:TableSetCurPage('" + self.name + "', this.value);\" />" : "");
                self.gotoPage.className = (self.topDiv.getAttribute("GoToPageCss") ? self.topDiv.getAttribute("GoToPageCss") : "def_gotopage_css");
            }

            if (self.rowsCnt) {
                var cnt_sbscr = (self.rowsCnt.getAttribute("sbscr") ? self.rowsCnt.getAttribute("sbscr") : "total: ");
                self.rowsCnt.innerHTML = cnt_sbscr + self.rowsTotal;
                self.rowsCnt.className = (self.topDiv.getAttribute("RowsCntCss") ? self.topDiv.getAttribute("RowsCntCss") : "def_rowscnt_css");
            }
        }

    self.addEditEvent = function (row, coldef, add)
        {
            var cell = row.cells[coldef.cnIndex];
            if (!cell) return;
            RmvHandler(cell, "click", self.DoEdit);
            cell.style.cursor = "";
            if(add && coldef.cnEditType == fType.Check)
                disableCtrl(cell.firstChild, eq(cell.getAttribute("pat_readonlyObj"),"True"));
            if(add && (row == self.curRow || self.OneClickEdit) && coldef.cnEditType != fType.Check && coldef.cnEditType != fType.Delete && coldef.cnEditType != fType.Custom && coldef.cnEditType != fType.Multsel && coldef.cnEditType != fType.None && (row.dbid == "-1" && !self.LockedInsR || row.dbid != "-1" && !self.LockedBody) && !eq(cell.getAttribute("pat_readonlyObj"),"True"))
            {
                AddHandler(cell, "click", self.DoEdit);
                cell.style.cursor = "text";
            }
        }

    self.setCell = function (row, coldef, val, DataRow)
        {
            if(row == null) return;
            
            var cell = row.cells[coldef.cnIndex];
            var isIns = (row.dbid == "-1");
            coldef.cnValues[row.dbid] = val;
            if (val == null && (coldef.cnEditType == fType.Select || coldef.cnEditType == fType.DDEx)) coldef.cnValues[row.dbid] = coldef.cnPdNullValue;
            
            self.LoadDepends(row, coldef);
            
            AddHandler(cell, "mouseover", self.cellMouseOver);
            AddHandler(cell, "mouseout", self.cellMouseOut);

            cell.className = "";
            
            var ReadonlyByVal = (row.dbid != "-1" && self.ReadOnly) || coldef.cnReadonly || (self.ReadonlyBy && self.ReadonlyBy !="" && DataRow && DataRow[self.ReadonlyBy] == 1) || (coldef.cnReadonlyBy && coldef.cnReadonlyBy !="" && DataRow && DataRow[coldef.cnReadonlyBy] == 1);
            cell.setAttribute("pat_readonlyObj", ReadonlyByVal ? "True" : "False");

            if(val == null) val = (coldef.cnEditType == fType.Select ? "null" : "");

            if(self.RowTip && DataRow && DataRow[self.RowTip]) row.setAttribute("title", DataRow[self.RowTip]); else  row.setAttribute("title", "");
            if(self.RowBackColor && DataRow && DataRow[self.RowBackColor]) row.style.backgroundColor = DataRow[self.RowBackColor]; else row.style.backgroundColor = "";
            if(coldef.cnTip && DataRow && DataRow[coldef.cnTip]) cell.setAttribute("title", DataRow[coldef.cnTip]); 
            else if(coldef.cnTip) cell.setAttribute("title", coldef.cnTip); else cell.setAttribute("title", ""); 
            
	        switch (coldef.cnEditType)
            {
                case fType.Check:
                    var chk = cell.firstChild;
                    if(chk == null)
                    {
			            chk = document.createElement("INPUT");
			            chk.type = "checkbox";
			            cell.appendChild(chk);
                        AddHandler(chk, "click", self.DoEditChk);
                        AddHandler(cell.childNodes[0], "keydown", self.TextKeyEvent);
                    }
                    chk.checked = val;
                    disableCtrl(chk, eq(cell.getAttribute("pat_readonlyObj"),"True"));
                    break;
                case fType.Datetime:
                case fType.Text:
                case fType.None:
                case fType.Textarea:
                    cell.innerHTML = "<div class='def_valuediv_css' onselectstart='return false;'>" + self.FormatValue(val, coldef) + "</div>";
                    if(coldef.cnEditType == fType.Textarea) cell.style.whiteSpace = "normal";
                    if (coldef.cnSpellCheck && (typeof (PNWSpeller) != "undefined") && (PNWSpeller != null) && (row.dbid != "-1" || row.dbid == "-1" && self.SpellCheckInsRow))
						SpellDecorate(cell, "en", self.simulateEndEdit, coldef.cnNoGrammarCheck);
                    break;
                case fType.Money:
                    cell.innerHTML = "<div class='def_valuediv_css' onselectstart='return false;'> $ " + FormatMoney(val) + "</div>";
                    break;
                case fType.Html:
                    cell.innerHTML = "<div class='def_valuediv_css' onselectstart='return false;'>" + val + "</div>";
                    break    
                case fType.Delete:
                    if(!isIns && self.DeleteMode)
                        if(ReadonlyByVal)
                            cell.innerHTML = "<img title='Delete Row' alt='Delete Row' src='" + self.DeleteGrayImg + "' style='border: 0' />";
                        else
                            cell.innerHTML = "<img title='Delete Row' alt='Delete Row' src='" + self.DeleteImg + "' style='border: 0' onclick=\"if(this.getAttribute('disabled') != 'disabled'){ TableDelRow('" + self.name + "', '" + row.dbid + "', '" + self.delConfirm + "'); event.cancelBubble = true;}\" />";
                    break;
                case fType.Custom:
                    if(coldef.cnCellTemplFnc)
                        ExecEx(coldef, "cnCellTemplFnc", {obj: self, row: row, coldef: coldef, cell: cell, val: val});
                    else
                        cell.innerHTML = coldef.cnCellTemplIH;
                    break;
                case fType.Multsel:
                    var chk = cell.firstChild;
                    if(chk == null)
                    {
			            chk = document.createElement("INPUT");
			            chk.type = "checkbox";
			            cell.appendChild(chk);
                        AddHandler(chk, "click", self.SelectRowOnCheck);
                    }
                    break;
            }
            
            if(cell.firstChild && cell.firstChild.tagName && eq(cell.firstChild.tagName, "DIV"))
            {
                cell.firstChild.style.width = self.headRow.cells[coldef.cnIndex].style.width;
                cell.firstChild.style.textAlign = self.headRow.cells[coldef.cnIndex].style.textAlign;
                cell.firstChild.style.verticalAlign = "middle";
            }
            else
            {
                cell.style.width = self.headRow.cells[coldef.cnIndex].style.width;
                cell.style.textAlign = self.headRow.cells[coldef.cnIndex].style.textAlign;
                cell.style.verticalAlign = "middle";
            }

            if(cell.firstChild && cell.firstChild.tagName && eq(cell.firstChild.tagName, "DIV") && coldef.cnWordWrap)
                cell.firstChild.className = cell.firstChild.className + " def_valuedivWW_css";
            
            if(cell.firstChild && cell.firstChild.tagName && eq(cell.firstChild.tagName,"DIV") && eq(cell.getAttribute("pat_readonlyObj"),"True"))
                cell.firstChild.className = cell.firstChild.className + " " + self.ReadonlyCss;

            cell.style.backgroundColor = ExecEx(coldef, "cnGetSellColorFnct", {obj: self, val: val});
            cell.className = cell.className + (coldef.cnCellCss != "" ? " " : "") + coldef.cnCellCss;

            if(DataRow != null && coldef.cnBackColor != null && DataRow[coldef.cnBackColor] != null)
            {
                cell.style.backgroundColor = DataRow[coldef.cnBackColor];
                cell.style.color = self.CalcTxtColor(DataRow[coldef.cnBackColor]);
            }
            
            if(self.OneClickEdit) self.addEditEvent(row, coldef, true)
        }

    self.SelectRowOnCheck = function (chk, evt)
        {
            if(!eq(chk.tagName, "input")) return;
            self.SelectRow(chk.parentNode.parentNode.dbid,chk.checked);
            if(chk.parentNode.parentNode == self.curRow && !chk.checked) self.UnselectCurRow();
            CancelBubbling(evt);
        }

    self.CalcTxtColor = function (backColor) 
        {            
            if(!backColor || backColor.length != 7) return "#000000";
            var res = "#";
            for(var i=1; i<7; i++)
            {
                var l = backColor.substring(i,i+1);
                res += (isNaN(l) || l>8 ? "0" : "F");
            }
            return res;
        }

    self.DelRow = function (row, confirm) 
        {             
            if (confirm == "" || window.confirm(confirm)) ServerCall("DelRow", self, {rowId: row, args: self.args});
        }

    self.OnDelRowRes = function (res)
        {
            if (res["errCode"] != null) return OnErr({obj: self, msg: res["errCode"]});
            self.LoadData(); 
            DataChangeNotify(self.DataChangeNotifyList, {act: "table_delrow", rowId: res["args"]["rowId"]});
        }

    self.EndEdit_ = function (inp, evt)
        {
            self.EndEdit(inp, null, null);
        }

	self.simulateEndEdit = function(ctrl, val)
	{
		self.EndEdit(ctrl, val, true);
	}

    self.EndEdit = function (oc, newValue, skipSpell)
        {
            while(oc != null && !eq(oc.tagName,"TD")) oc = oc.parentNode;
            if (oc == null || !self.theEditor) return;

            var row = oc.parentNode;
            var val;
            var coldef = self.colDefs[oc.getAttribute("columnIndex")];
            
            switch (coldef.cnEditType)
            {
                case fType.Money:
					if (newValue != null)
						val = newValue;
					else
						val = self.theEditor.value;

                    if (!self.isValid(coldef, val)) return self.cancelEdit();
                    oc.firstChild.innerHTML = " $ " + FormatMoney(val);
                    break;
                case fType.Text:
                case fType.Textarea:
                case fType.Html:
					if (newValue != null)
						val = newValue;
					else
						val = self.theEditor.value;

                    if (!self.isValid(coldef, val)) return self.cancelEdit();
                    oc.firstChild.innerHTML = self.FormatValue(val, coldef);
                    break;
                case fType.Datetime:
                    if(self.theEditor.firstChild.firstChild.firstChild.firstChild.firstChild)
                        val = self.theEditor.firstChild.firstChild.firstChild.firstChild.firstChild.value;
                    else
                        val = self.theEditor.firstChild.firstChild.firstChild.firstChild.value;
                    if (!self.isValid(coldef, val)) return self.cancelEdit();
                    oc.firstChild.innerHTML = self.FormatValue(val, coldef);
                    hideCalendar();
                    break;
                case fType.Select:
                    val = self.theEditor.value;
                    if(val == "null") val = null;
                    if (!self.isValid(coldef, val)) return self.cancelEdit();
                    if(self.theEditor.selectedIndex > -1) oc.style.backgroundColor = self.theEditor.options[self.theEditor.selectedIndex].style.backgroundColor;
                    break;
                case fType.DDEx:
                    val = DDExValue("TableEditDDEx_" + row.dbid + "_" + coldef.cnIndex);
                    if(val == "null") val = null;
                    if (!self.isValid(coldef, val)) return self.cancelEdit();
                    break;
                case fType.Check:
                    break;
            }
            var oldVal = "" + coldef.cnValues[row.dbid];
            val = "" + val;
            var changed = (coldef.cnEditType != fType.Datetime && oldVal.replace(/\r\n/g,"<BR>").replace(/\n/g,"<BR>").replace(/\r/g,"<BR>") != val.replace(/\r\n/g,"<BR>").replace(/\n/g,"<BR>").replace(/\r/g,"<BR>") || coldef.cnEditType == fType.Datetime && new Date(val).format("MM/dd/yyyy") != new Date(oldVal).format("MM/dd/yyyy"));
            var oldval = coldef.cnValues[row.dbid];
            coldef.cnValues[row.dbid] = val;
            if (row.dbid != "-1" && changed)
            {
                ServerCall("SetData", self, {rowId: row.dbid, field: coldef.cnDBName, value: val, oldval: oldval, args: self.args});
                // !!! Moved here from onSetDataRes
                DataChangeNotify(self.DataChangeNotifyList, {act: "table_setdata", rowId: row.dbid});
            }
            
            self.SwitchTableEditToView();
            
            self.LoadDepends(row, coldef);

            var datarow = self.GetDataRow(row.dbid);
            if(datarow) datarow[coldef.cnDBName] = val;
            
	        if (!skipSpell && coldef.cnSpellCheck && (typeof(PNWSpeller) != "undefined") && (PNWSpeller != null) && (row.dbid != "-1" || row.dbid == "-1" && self.SpellCheckInsRow))
				SpellDecorate(oc, "en", self.simulateEndEdit, coldef.cnNoGrammarCheck);
        }
        
        self.SwitchTableEditToView = function()
        {
            if(self.theEditor == null) return; 
            
            var cell = self.theEditor;
            while(cell != null && !eq(cell.tagName,"TD")) cell = cell.parentNode;
            if(cell == null) return OnErr({obj: self, msg: "Wrong table html"});

            var coldef = self.colDefs[cell.getAttribute("columnIndex")];
            if(coldef && (coldef.cnEditType == fType.Select || coldef.cnEditType == fType.DDEx)) { self.theEditor = null; return self.SetPullDownCell(cell,coldef); }
            
            AutoCompleteDel(self.theEditor.id); // if it was AutoComplete all attached events will be deleted
            var edt = self.theEditor;
            while(edt.parentNode != null && !eq(edt.parentNode.tagName.toUpperCase(),"TD")) edt = edt.parentNode;
            if(edt.parentNode == null || edt.parentNode.firstChild == null || !eq(edt.parentNode.firstChild.tagName,"DIV")) return OnErr({obj: self, msg: "Wrong table html"});
            edt.style.display = "none";
            edt.parentNode.firstChild.style.display = "";
            window.setTimeout(function(){if(edt && edt.parentNode) edt.parentNode.removeChild(edt);}, 1); 
            self.theEditor = null;
        }

        self.OnSetDataRes = function(res) {
            var rowId = res["args"]["rowId"];
            var field = res["args"]["field"];
            var value = res["args"]["value"];
            var oldval = res["args"]["oldval"];
            var scalarRes = res["scalarRes"];

            for (var j = 0; j < self.colDefs.length && self.colDefs[j].cnDBName != field; j++);
            if (res["errCode"] != null) {
                var row = self.Row(rowId);

                self.setCell(row, self.colDefs[j], oldval, null);
                if (self.colDefs[j].cnEditType == fType.Select || self.colDefs[j].cnEditType == fType.DDEx) self.SetPullDownCell(row.cells[j], self.colDefs[j]);
                return OnErr({obj: self, msg: res["errCode"]});
            } else {
                if (self.colDefs[j].RefreshTableOnChange) self.LoadData();
            }

            if (self.RefreshRowOnChange || self.colDefs[j].RefreshFieldOnChange) self.RefreshRow(rowId, self.colDefs[j].RefreshFieldOnChange);
        }

    self.DoEditChk = function (chk, evt)
        {
            if(!eq(chk.tagName, "input")) return;
            self.DoEdit(chk.parentNode,  evt);
        }

        self.DoEdit = function(cell, evt) {
            if ((evt != null && evt.ctrlKey) || !eq(cell.tagName, "td") || cell.firstChild == null || cell.firstChild.style == null || eq(cell.firstChild.style.display, "NONE")) return;
            var row = cell.parentNode;
            if (self.theEditor) self.EndEdit(self.theEditor, null, null);
            var coldef = self.colDefs[cell.getAttribute("columnIndex")];
            switch (coldef.cnEditType) {
                case fType.Text:
                    var EditSpan = document.createElement("span");
                    EditSpan.id = "TableEditObj";

                    cell.firstChild.style.display = "none";
                    cell.appendChild(EditSpan);

                    self.theEditor = document.createElement("INPUT");
                    self.theEditor.type = "text";
                    self.theEditor.style.width = (cell.offsetWidth - 17).toString() + "px";
                    self.theEditor.style.height = (cell.offsetHeight - 10).toString() + "px";
                    self.theEditor.id = "TableEdit";
                    EditSpan.appendChild(self.theEditor);

                    self.theEditor.value = coldef.cnValues[row.dbid] == null ? "" : coldef.cnValues[row.dbid];

                    if (coldef.cnRelTableName) {
                        self.theEditor.setAttribute("autocomplete", "off");

                        self.theEditor.setAttribute("cnRelTableName", coldef.cnRelTableName);
                        if (coldef.cnRelColors) self.theEditor.setAttribute("cnRelColors", coldef.cnRelColors);
                        if (coldef.cnRelNames) self.theEditor.setAttribute("cnRelNames", coldef.cnRelNames);
                        if (coldef.cnRelBackColor) self.theEditor.setAttribute("cnRelBackColor", coldef.cnRelBackColor);
                        if (coldef.cnRelSplitter) self.theEditor.setAttribute("cnRelSplitter", coldef.cnRelSplitter);
                        if (coldef.cnMaxOpts) self.theEditor.setAttribute("cnMaxOpts", coldef.cnMaxOpts);
                        if (coldef.cnColumn) self.theEditor.setAttribute("cnColumn", coldef.cnColumn);
                        if (coldef.cnVColumn) self.theEditor.setAttribute("cnVColumn", coldef.cnVColumn);
                        if (coldef.cnFilter) self.theEditor.setAttribute("cnFilter", coldef.cnFilter);
                        if (coldef.divW) self.theEditor.setAttribute("divW", coldef.divW);
                        if (coldef.divH) self.theEditor.setAttribute("divH", coldef.divH);

                        self.theEditor.setAttribute("onHide", "TableEndEdit('" + self.name + "')");
                        //AddHandler(self.theEditor, "blur", self.EndEdit_);

                        window.setTimeout(function() { if (self.theEditor) AutoCompleteInit(self.theEditor.id); }, 5);
                    }
                    else {
                        AddHandler(self.theEditor, "blur", self.EndEdit_);
                    }
                    self.theEditor.focus();
                    AddHandler(self.theEditor, "keydown", self.TextKeyEvent);
                    break;
                case fType.Money:
                    self.theEditor = document.createElement("INPUT");
                    self.theEditor.type = "text";
                    self.theEditor.style.width = (cell.offsetWidth - 17).toString() + "px";
                    self.theEditor.style.height = (cell.offsetHeight - 10).toString() + "px";
                    self.theEditor.id = "TableEdit";

                    AddHandler(self.theEditor, "keydown", self.TextKeyEvent);
                    AddHandler(self.theEditor, "blur", self.EndEdit_);
                    self.theEditor.onkeydown = function(evt) { return ImpEventMoneyFormatCheck(this, (evt ? evt : window.event)); };

                    cell.firstChild.style.display = "none";
                    cell.appendChild(self.theEditor);

                    self.theEditor.value = FormatMoney(coldef.cnValues[row.dbid]);
                    self.theEditor.focus();
                    break;
                case fType.Textarea:
                case fType.Html:
                    self.theEditor = document.createElement("textarea");
                    self.theEditor.style.width = (cell.offsetWidth - 17).toString() + "px";
                    self.theEditor.style.height = (cell.offsetHeight - 9).toString() + "px";
                    self.theEditor.className = self.TextAreaCss;
                    self.theEditor.id = "TableTextArea";

                    AddHandler(self.theEditor, "keydown", self.TextKeyEvent);
                    AddHandler(self.theEditor, "blur", self.EndEdit_);

                    self.theEditor.value = coldef.cnValues[row.dbid];
                    cell.firstChild.style.display = "none";
                    cell.appendChild(self.theEditor);
                    self.theEditor.focus();
                    break;
                case fType.Datetime:
                    self.theEditor = document.createElement("span");
                    self.theEditor.id = "ClndObj_" + coldef.cnIndex + "_" + row.dbid;

                    AddHandler(self.theEditor, "keydown", self.TextKeyEvent);
                    //AddHandler(self.theEditor, "blur", self.EndEdit_);

                    cell.firstChild.style.display = "none";
                    cell.appendChild(self.theEditor);
                    //ClndInit(self.theEditor.id, coldef.cnValues[row.dbid]);
                    //CreateCalendar(placeHolder, value, inpCss, onEndEditFunction, showbtn, opened)
                    CreateCalendar(self.theEditor, coldef.cnValues[row.dbid], "CalendarImp", self.EndEdit, false, true);
                    AddHandler(self.theEditor, "blur", self.EndEdit_);
                    self.theEditor.focus();
                    break;
                case fType.DDEx:
                    var EditDiv = document.createElement("div");
                    EditDiv.id = "TableEditDDEx_" + row.dbid + "_" + coldef.cnIndex;

                    cell.firstChild.style.display = "none";
                    cell.appendChild(EditDiv);

                    if (coldef.cnRelTableName) {
                        EditDiv.setAttribute("cnRelTableName", coldef.cnRelTableName);
                        EditDiv.setAttribute("opened", "True");
                        if (coldef.cnRelColors) EditDiv.setAttribute("cnRelColors", coldef.cnRelColors);
                        if (coldef.cnRelNamesStr) EditDiv.setAttribute("cnRelNames", coldef.cnRelNamesStr);
                        if (coldef.cnRelBackColor) EditDiv.setAttribute("cnRelBackColor", coldef.cnRelBackColor);
                        if (coldef.cnRelSplitter) EditDiv.setAttribute("cnRelSplitter", coldef.cnRelSplitter);
                        if (coldef.cnMaxOpts) EditDiv.setAttribute("cnMaxOpts", coldef.cnMaxOpts);
                        if (coldef.cnColumn) EditDiv.setAttribute("cnColumn", coldef.cnColumn);
                        if (coldef.cnVColumn) EditDiv.setAttribute("cnVColumn", coldef.cnVColumn);
                        if (coldef.divW) EditDiv.setAttribute("divW", coldef.divW);
                        if (coldef.divH) EditDiv.setAttribute("divH", coldef.divH);

                        EditDiv.setAttribute("impW", coldef.impW ? coldef.impW : (cell.offsetWidth - 20) + "px");
                        EditDiv.setAttribute("onHide", "TableEndEdit('" + self.name + "'); DDExDel('" + EditDiv.id + "');");
                    }

                    self.theEditor = cell;
                    self.theEditorObj = DDExInit(EditDiv.id, self.args);
                    DDExSetValue(EditDiv.id, coldef.cnValues[row.dbid] == null ? "" : coldef.cnValues[row.dbid]);
                    if (objList[EditDiv.id]) objList[EditDiv.id].onValueChanged = function() { TableEndEdit(self.name); DDExDel(EditDiv.id); }

                    break;
                case fType.Select:
                    self.theEditor = document.createElement("SELECT");
                    self.theEditor.style.width = (cell.offsetWidth - 12).toString() + "px";
                    self.theEditor.style.height = (cell.offsetHeight - 2).toString() + "px";

                    self.theEditor.id = "TablePullDown";

                    self.SetPullDownOptions(coldef, self.theEditor, row);

                    AddHandler(self.theEditor, "keydown", self.TextKeyEvent);
                    AddHandler(self.theEditor, "change", self.EndEdit_);
                    AddHandler(self.theEditor, "blur", self.EndEdit_);

                    cell.firstChild.style.display = "none";
                    cell.appendChild(self.theEditor);
                    if (self.theEditor.value != coldef.cnValues[row.dbid]) self.theEditor.value = coldef.cnValues[row.dbid];
                    self.theEditor.focus();
                    break;
                case fType.Check:
                    coldef.cnValues[row.dbid] = cell.childNodes[0].checked;
                    if (row.dbid != "-1") {
                        ServerCall("SetData", self, { rowId: row.dbid, field: coldef.cnDBName, value: cell.childNodes[0].checked, oldval: !cell.childNodes[0].checked, args: self.args });
                        DataChangeNotify(self.DataChangeNotifyList, { act: "table_setdata", rowId: row.dbid });
                    }
                    break;
            }
        }

    self.SelectRowByRow = function (row, evt)
        {
            if(!row) {self.UnselectCurRow(); return;}
            if(!eq(row.tagName, "tr")) return;
            
            if(evt && evt.ctrlKey && self.multSel)
            {
                if(row == self.curRow)
                {
                    self.UnselectCurRow();
                    ExecEx(self, "onSelRow", {obj: self, curRowId: (self.curRow ? "" + self.curRow.dbid : "")});
                    RowChangeNotify(self.RowChangeNotifyList, {rowId: -1, rowidname: self.DbRowId});
                    ExecEx(self, "onRowSelected", {obj: self, curRowId: (self.curRow ? "" + self.curRow.dbid : "")});
                }
                else
                    self.SelectRow(row.dbid,self.selRowsId[row.dbid] != true);

                return;
            }
            else if(evt && evt.shiftKey && self.multSel && self.curRow)
            {
                var go = false;
                for (var i = 0; i < self.TableRows.length; i++)
                {
		            if(self.TableRows[i] == self.curRow || self.TableRows[i] == row) go = !go;
		            if(go || self.TableRows[i] == self.curRow || self.TableRows[i] == row)
                        self.SelectRow(self.TableRows[i].dbid,true);
		        }
                return;
            }
            
            ExecEx(self, "onNewRow", {obj: self, rowId: (row ? row.dbid : "''")});
            if(row == self.curRow) return;

            self.ClearAllSelection();
            self.SelectCurRow(row);
            
            if(self.HideRowsOnSelect) self.HideRows_();
            
            ExecEx(self, "onSelRow", {obj: self, curRowId: (self.curRow ? "" + self.curRow.dbid : "")});
            RowChangeNotify(self.RowChangeNotifyList, self.curRow ? {rowId: self.curRow.dbid, rowidname: self.DbRowId} : null);
            ExecEx(self, "onRowSelected", {obj: self, rowId: (self.curRow ? "" + self.curRow.dbid : "")});
        }

    self.Row = function (id)
    {
        for (var i = 0; i < self.TableRows.length; i++)
	        if(self.TableRows[i].dbid == id)
	            return self.TableRows[i];
	    if(id == "-1") return self.insRow;
        return null;
	}

    self.SelectAllRows = function (sel)
    {
        for (var i = 0; i < self.TableRows.length; i++)
            self.SelectRow(self.TableRows[i].dbid, sel);
    }

    self.SelectRow = function (id, sel)
    {
        var row = self.Row(id);
        
        if(sel)
        {
            if(self.multSel || self.curRow.dbid == id) self.selRowsId[id] = true;
        }
        else
            delete self.selRowsId[id];

        if(row)row.className = (sel ? self.SelRowCss : self.RowCss);
        for (var j = 0; j < self.colDefs.length; j++)
            if(row && self.colDefs[j].cnEditType == fType.Multsel && row.cells[j].firstChild) row.cells[j].firstChild.checked = sel;
        ExecEx(self, "onSelRowsChanged", {obj: self, selRowsId: self.selRowsId, rowId: id, selected: sel});
    }

    self.SelectCurRow = function (row)
    {
        self.curRow = row;
        self.SelectRow(row.dbid,true);
        if (!self.OneClickEdit && self.curRow) 
            for (var j = 0; j < self.colDefs.length; j++) self.addEditEvent(self.curRow, self.colDefs[j], true);
    }

    self.UnselectCurRow = function (LeaveSelected)
    {
        if(!self.curRow) return;
        if(!LeaveSelected)self.SelectRow(self.curRow.dbid, false);
        for (var j = 0; j < self.colDefs.length; j++)
        {
			if(!self.OneClickEdit) self.addEditEvent(self.curRow, self.colDefs[j], false);
			if (self.colDefs[j].cnSpellCheck && (typeof(PNWSpeller) != "undefined") && (PNWSpeller != null))
			{
				var td = self.curRow.cells[self.colDefs[j].cnIndex];
				if (((typeof (td.decorator) == "undefined") || (td.decorator == null) || !td.decorator.stuffed) && (self.curRow.dbid != "-1" || self.curRow.dbid == "-1" && self.SpellCheckInsRow))
					SpellDecorate(td, "en", self.simulateEndEdit, self.colDefs[j].cnNoGrammarCheck);
			}
		}
        self.curRow = null;
        ExecEx(self, "onRowSelected", {obj: self, curRowId: (self.curRow ? "" + self.curRow.dbid : "")});
    }

    self.ClearAllSelection = function ()
    {
        for (var id in self.selRowsId) 
        {
            self.SelectRow(id, false);
            delete self.selRowsId[id];
        }
        self.UnselectCurRow();
    }

    self.LockTable = function(disable, disableIns) {
        if (disable == null) disable = true;
        if (disableIns == null) disableIns = disable;
        self.LockedBody = disable;
        self.LockedInsR = disableIns;
        
        self.LockRow(self.insRow, disableIns);

        if (!self.TableRows) return;

        for (var i = 0; i < self.TableRows.length; i++)
            self.LockRow(self.TableRows[i], disable);
    }
    
    self.Disable = function(disable) {
        self.LockTable(disable, disable);
    }    

    self.LockRow = function(row, lock) 
    {
        if (!row) return;
        for (var j = 0; j < self.colDefs.length; j++) {
            var coldef = self.colDefs[j];

            disableCtrl(row.cells[coldef.cnIndex], lock);
            self.addEditEvent(row, coldef, !lock);
        }
    }
    
    self.InsertRow = function() 
    {
        var n = new Array();
        var o = new Array();
        var ln = 0;
        for (var i = 0; i < self.colDefs.length; i++) {
            var coldef = self.colDefs[i];
            if (coldef.cnDBName == null || coldef.cnDBName == "") continue;
            switch (coldef.cnEditType) {
                case fType.Text: case fType.Textarea: case fType.Check: case fType.Money: case fType.Html: case fType.Select: case fType.Datetime:
                    if (eq(self.insRow.cells[coldef.cnIndex].getAttribute("pat_readonlyObj"),"True")) break;
                    o[ln] = (self.insRow == null ? coldef.cnDefVal : coldef.cnValues["-1"]);
                    n[ln++] = coldef.cnDBName;
                    break;
                case fType.Custom:
                    if (coldef.cnCustomValue == "" || eq(self.insRow.cells[coldef.cnIndex].getAttribute("pat_readonlyObj"),"True")) break;
                    o[ln] = self.insRow[coldef.cnCustomValue];
                    n[ln++] = coldef.cnDBName;
                    break;
            }
            if (!self.isValid(coldef, o[ln - 1])) return;
        }

        ServerCall("InsRow", self, {insNames: n, insArgs: o, args: self.args});
    }
    
    self.InsertRowEF = function() 
    {
        var n = new Array(self.colDefs.lenght);
        var o = new Array(self.colDefs.lenght);
        var ln = 0;
        for (var i = 0; i < self.colDefs.length; i++) {
            var coldef = self.colDefs[i];
            var imp = coldef.cnEditFormInput;
            if (coldef.cnDBName == null || coldef.cnDBName == "") continue;
            if (coldef.cnReadonly) continue;

            switch (coldef.cnEditType) {
                case fType.Text: case fType.Textarea: case fType.Money: case fType.Html: case fType.Select:
                    o[ln] = (imp == null ? coldef.cnDefVal : imp.value);
                    n[ln++] = coldef.cnDBName;
                    break;
                case fType.Check:
                    o[ln] = (imp == null ? coldef.cnDefVal : imp.checked);
                    n[ln++] = coldef.cnDBName;
                    break;
                case fType.Datetime:
                    o[ln] = (imp == null ? coldef.cnDefVal : imp.value);// (imp.firstChild.firstChild.firstChild.firstChild.firstChild ? imp.firstChild.firstChild.firstChild.firstChild.firstChild.value : imp.firstChild.firstChild.firstChild.firstChild.value));
                    n[ln++] = coldef.cnDBName;
                    break;
                case fType.Custom:
                    break;
            }
            if (!self.isValid(coldef, o[ln - 1])) return;
        }

        ServerCall("InsRow", self, {insNames: n, insArgs: o, args: self.args, popUp : self.name + "_Inner"});
    }

    self.OnInsRowRes = function (res)
        {
            if (res["errCode"] != null) return OnErr({obj: self, msg: res["errCode"]});
            if(res.args.popUp) 
            {
                PopUpShow(res.args.popUp, false);
                delete res.args.popUp;
            }
            self.LoadData();
            DataChangeNotify(self.DataChangeNotifyList, {act: "table_insrow"});
        }

    self.TextKeyEvent = function (inp, evt)
        {
            var cell = inp.parentNode;
            while(cell.parentNode != null && !eq(cell.tagName, "TD")) cell = cell.parentNode;
            var type = self.colDefs.length > cell.getAttribute("columnIndex") ? self.colDefs[cell.getAttribute("columnIndex")].cnEditType : fType.None;
            if(!eq(cell.tagName, "td")) return;            
            switch(evt.keyCode)
            {
                case ESC_KEY_CODE:
                    window.setTimeout(function(){self.cancelEdit();}, 1);
                    break;
                case ENTER_KEY_CODE:
                    if(type != fType.Textarea) window.setTimeout(function(){self.EndEdit(cell);}, 1); 
                    break;
                case TAB_KEY_CODE:
                    var cd = null, cl = null, row = self.curRow;

                    if(type != fType.Check && type != fType.Datetime) self.EndEdit(cell);
                    if(type == fType.Datetime) hideCalendar();
                    
                    cl = self.getNextEditCellInRow(row, cell.getAttribute("columnIndex"));
                    if(cl ==null && row == self.insRow && self.InsertRowOnTab)
                    {
                        self.args["SelectFirstInsCell"] = 1;
                        return self.InsertRow();
                    }
                    while(!cl)
                    {
                        row = self.getNextRow(row);
		                if(!row) break;
		                cl = self.getNextEditCellInRow(row, 0);
                    }

                    self.selectCell(cl, row);
                    break;
            }
        }

    self.selectCell = function (cl, row)
    {
        if(!cl) return;
        if(row != self.curRow) self.SetCurRow(row.dbid);

        if(self.colDefs[cl.getAttribute("columnIndex")].cnEditType != fType.Check)
            return window.setTimeout(function(){self.DoEdit(cl, null);}, 300); // let finish onEdit reaction before (important!!!)
        else
            return window.setTimeout(function(){cl.firstChild.focus();}, 300);
    }

    self.getNextRow = function (row)
    {
        if(row == self.insRow)
        {
            if(self.TableRows.length > 0)
                return self.TableRows[0];
            else 
                return null;
        }
        for (var i = 0; i < self.TableRows.length; i++)
            if(self.TableRows[i] == row && i + 1 < self.TableRows.length)
                return self.TableRows[i + 1];
        return null;
    }

    self.getNextEditCellInRow = function (row, cellnum)
    {
        if(!row) return null;
        for(var i=parseInt(cellnum) + 1; i<self.colDefs.length; i++)
            if(!eq(row.cells[self.colDefs[i].cnIndex].getAttribute("pat_readonlyObj"),"True") && self.colDefs[i].cnEditType != fType.Delete && self.colDefs[i].cnEditType != fType.Custom && self.colDefs[i].cnEditType != fType.None)
                return row.cells[self.colDefs[i].cnIndex];
        return null;
    }

    self.cancelEdit = function ()
        {
            self.SwitchTableEditToView();
        }

    self.isValid = function (coldef, val)
        {
            if(coldef == null || coldef.cnValidate == null) return true;
            var result = ExecEx(coldef, "cnValidate", {obj: self, val: val});
            if (!result) OnErr({obj: self, msg: "Incorrect " + coldef.cnTitle, val: val});
            return result;
        }
    
    self.rowMouseOver = function (row, evt)
        {
            if(!eq(row.tagName, "tr")) return;
            if (row != self.curRow && self.selRowsId[row.dbid] != true) row.className = self.MouseOverRowCss;
            if(self.CustomRowTip && self.theEditor == null)
            {
                if(!eq(self.tipdiv.parentNode.tagName,"BODY")) document.body.appendChild(self.tipdiv);
                ExecEx(self, "CustomRowTip", {obj: self, row: row, tip: self.tipdiv});

	            if(self.tiptimer) window.clearTimeout(self.tiptimer);
                var doc = (document.compatMode && document.compatMode=="CSS1Compat") ? document.documentElement : document.body;
	            var X = evt.clientX + doc.scrollLeft + 3, Y = evt.clientY + doc.scrollTop + 3;
	            if(trim(self.tipdiv.innerHTML) != "") self.tiptimer = window.setTimeout(function() { ShowPopUpByCords(self.tipdiv, X, Y); }, 300);
            }
            ExecEx(self, "onRowMouseOver", {obj: self, row: row, evt: evt});
        }
    self.rowMouseOut = function (row, evt)
        {
            if(!eq(row.tagName, "tr")) return;
            if (row != self.curRow && self.selRowsId[row.dbid] != true) row.className = self.RowCss;
            if(self.tiptimer) window.clearTimeout(self.tiptimer);
            if(self.CustomRowTip) HidePopUp(self.tipdiv);
            ExecEx(self, "onRowMouseOut", {obj: self, row: row, evt: evt});
        }
    
    self.cellMouseOver = function (td, evt)
        {
            if(!eq(td.tagName, "td")) return;
            var coldef = self.colDefs[td.getAttribute("columnIndex")];
            if(coldef.cnCstmTip && self.theEditor == null)
            {
                if(!eq(self.tipdiv.parentNode.tagName,"BODY")) document.body.appendChild(self.tipdiv);
                ExecEx(coldef, "cnCstmTip", {obj: self, id: td.parentNode.dbid, tip: self.tipdiv, cd: coldef});

	            if(self.tiptimer) window.clearTimeout(self.tiptimer);
                var doc = (document.compatMode && document.compatMode=="CSS1Compat") ? document.documentElement : document.body;
	            var X = evt.clientX + doc.scrollLeft + 3, Y = evt.clientY + doc.scrollTop + 3;
	            if(trim(self.tipdiv.innerHTML) != "") self.tiptimer = window.setTimeout(function() { ShowPopUpByCords(self.tipdiv, X, Y); }, 300);
            }
        }
    self.cellMouseOut = function (td, evt)
        {
            if(!eq(td.tagName, "td")) return;
            var coldef = self.colDefs[td.getAttribute("columnIndex")];
            if(self.tiptimer) window.clearTimeout(self.tiptimer);
            if(coldef.cnCstmTip) HidePopUp(self.tipdiv);
        }

    self.FormatValue = function (val, coldef)
        {
            //we should formate Date now, and have only one attribut to format value by: cnMaxLen, but it is possible to have more format attributs
            var res = "" + val;
            
            if (coldef.cnFormat)
                res = ExecEx(coldef, "cnFormat", {obj: self, coldef: coldef, val: res});
            else {
                if (coldef.cnEditType == fType.Datetime && val != "")
                    try { res = new Date(val).format("MM/dd/yyyy"); } catch (er) {res = "";}
            }
            res = ((coldef.cnMaxLen && coldef.cnMaxLen > 0 && coldef.cnMaxLen < res.length) ? subval = res.substring(0,coldef.cnMaxLen) + "..." : res);
            if(coldef.cnEditType == fType.Text || coldef.cnEditType == fType.None || coldef.cnEditType == fType.Textarea)
            {
                var d = document.createElement("div");
                SetText(d,res);
                res = d.innerHTML;
            }
            if(coldef.cnEditType == fType.Textarea) {
                res = res.replace(/\cM\cJ/gm,"<br>");
                res = res.replace(/\cJ/gm,"<br>");
            }

            return res;     
        }

    self.RenderPager = function (Step)
        {
	        var result = "";
	        if (self.pagesCount > 1)
	        {
	            if(Step < 1) Step = 1; // Step - num of additional page links before and after current page

	            var start = self.currentPage - Step;
	            if (start < 2) start = 2;

	            var finish = start + Step*2 + 1;
	            if (finish > self.pagesCount)
	            {
	                start -= (finish - self.pagesCount);
		            if (start < 2) start = 2;
	                finish = self.pagesCount;
	            }

                result += self.PagerCode(1);
                if(start > 2)result += "<div class=\"" + self.PagerSepCss + "\">...</div>";

	            for (var i = start; i < finish; i++)
	                result += self.PagerCode(i);

                if(finish < self.pagesCount)result += "<div class=\"" + self.PagerSepCss + "\">...</div>";
                result += self.PagerCode(self.pagesCount);
	        }
	        return result;
        }

    self.PagerCode = function (Page)
        {
            var Label = Page;
            if(self.pagerText) Label = ExecEx(self, "pagerText", {obj: self, page: Page});
            if (self.currentPage == Page) return "<div class=\"" + self.SelPagerCss + "\"><b>" + Label + "</b></div>";
            var funct = (self.pagerFunction == null ? "" : self.pagerFunction + "(" + Page + ");");
            return "<div class=\"" + self.PagerCss + "\" onclick=\"javascript:TableSetCurPage('" + self.name + "', " + Page + ");" + funct + "\">" + Label + "</div>";
        }

    if(self.HtmBlocks == null)self.SizeTable(0);
    self.LoadData();
}

//------------------------------------------------- Row Editor -------------------------------------------------
//--------------------------------------------------------------------------------------------------------------

function REInit(name, args, prms)
{
    return PatObj_Init(PatObjType.SRE, name, args, prms);
}

function RERefresh(name, args, rowId)
{
    if(objList[name]) {
        objList[name].Refresh(args, rowId);
    }
}

function RERowID(name) {
    if(objList[name]) return objList[name].args.rowId;
    return -1;
}

function REUpdateArgs(name,args){
    if(objList[name])
    {
        if(args) AddHash(objList[name].args, args);        
    }
}

function REDisable(name, dis)
{
    if(objList[name]) objList[name].Disable(dis);
}

function REClear(name)
{
    if(objList[name] && objList[name].ClearControls) objList[name].ClearControls();
}

function IsRELinked(name)
{
    var res = false;
    if (objList[name]) 
        res = objList[name].IsLinked();
    
    return res;
}

function REMakeInsert(name,args){
    if(args)AddHash(objList[name].args,args);
    objList[name].REInsertRow(true);
}

function RESave(name, inp)
{
    if(objList[name]) objList[name].REEndEdit(inp);
}

function RowEditor(name, args, prms)
{
    var self = objList[name];
    if(self == null) return OnErr({msg: "Can't init object", val: name});

    self.name = name;
    self.args = args;

    self.onServerCall = prms["onServerCall"];
    self.onServerRes = prms["onServerRes"];
    self.onDataLoaded = prms["onDataLoaded"];

    if(prms["rowId"]) self.args.rowId = prms["rowId"];

    self.DataChangeNotifyList = prms["DataChangeNotifyList"];
    self.alwaysEnabled = prms["alwaysEnabled"];

	self.controls = null;
    self.table = null;

    self.OnDataChangeNotification = function(params) 
        { 
            self.LoadData();
        }

    self.OnRowChangeNotification = function (params) 
        { 
            if(params != null && params["rowId"] != null)
                if(params["rowidname"] != null && params["rowidname"] != "rowId" && params["rowidname"] != "id")
                    self.args = AddHash(self.args, params["rowidname"], params["rowId"]);
                else
                    self.args.rowId = params["rowId"];
			self.LoadData();
        }

    self.OnServiceRes = function (res)
    {
        switch(res["cmdCode"])
        {
            case "GetSingleRow": self.OnGetSingleRowRes(res); break;
            case "SetData":      self.OnSetDataRes(res); break;
            case "InsRow":       self.OnInsRowRes(res); break;
        }
    }

    self.Refresh = function(args, rowId) {
        if (args) AddHash(self.args, args);
        if (rowId) self.args.rowId = rowId;
        self.LoadData();
    }

    self.LoadData = function ()
    {
        self.LoadControls();
        ServerCall("GetSingleRow", self, {rowId: self.args.rowId, args: self.args});
    }

    self.SetUpButtons = function ()
    {
        if(self.UpdateButton)
        {
            self.onValidateUpdate = self.UpdateButton.getAttribute("onValidate");
            disableCtrl(self.UpdateButton, self.args.rowId == "-1");
            AddHandler(self.UpdateButton, "click", self.REUpdateRow_);
        }
        if(self.InsertButton)
        {
            self.onValidateInsert = self.InsertButton.getAttribute("onValidate");
            disableCtrl(self.InsertButton, self.args.rowId != "-1" && !self.UpdateButton);
            AddHandler(self.InsertButton, "click", self.REInsertRow_);
        }
        if(self.ClearButton)
        {
            disableCtrl(self.ClearButton, self.args.rowId != "-1" && !self.UpdateButton);
            AddHandler(self.ClearButton, "click", self.REClear);
        }
        if(self.DeselectButton)
        {
            disableCtrl(self.DeselectButton, self.args.rowId == "-1");
            AddHandler(self.DeselectButton, "click", self.REDeselect);
        }
    }

	self.LoadControls = function()
	{
	    if(self.controls != null) return;
		self.controls = new Array();
		var rex = new RegExp("^(.+)_" + self.name + "$", "i");
		var docall = document.getElementsByTagName('*');
		for (var i = 0; i < docall.length; i++)
		{
			var el = rex.exec(docall[i].id);
            if (el == null) continue;
            if (el[1] == "UpdateButton")  { self.UpdateButton = docall[i]; continue; }
            if (el[1] == "InsertButton")  { self.InsertButton = docall[i]; continue; }
            if (el[1] == "ClearButton")   { self.ClearButton = docall[i]; continue; }
            if (el[1] == "DeselectButton"){ self.DeselectButton = docall[i]; continue; }
        
            var control = { Input:docall[i], Type:fieldType(docall[i]), Related:new Array() };
	        self.controls.push(control);
		}

		for (var i = 0; i < self.controls.length; i++)
		{
            var control = self.controls[i];
		    if(control.Type == fType.Select) 
		    {
		        control.Related = self.FindRelated(control.Input);
		        DDInit(control.Input.id, self.args); 
		    }
		    if(control.Type == fType.DDEx) 
		    {
		        control.Related = self.FindRelated(control.Input);
		        DDExInit(control.Input.id, self.args); 
		    }
		    if(control.Type == fType.Money)
		    {
                var pr = control.Input.parentNode;
                var t = document.createElement("table");  
                t.className = (control.Input.getAttribute("MoneyTableCss") ? control.Input.getAttribute("MoneyTableCss") : "def_emptytable_css");
                var r = t.insertRow(0);
                r.insertCell(0).appendChild(control.Input);
                r.insertCell(1).innerHTML = "&nbsp;$";

                pr.appendChild(t);
                control.Input.onkeydown = function(evt){return ImpEventMoneyFormatCheck(this, (evt ? evt : window.event)); };
		    }
		    if(control.Type == fType.Datetime)
		    {
		        if(control.Input.getAttribute("cnClndBtn") != "False")
		        {
		            control.Input.className += (control.Input.getAttribute("ClndInpCss") ? control.Input.getAttribute("ClndInpCss") : "def_clndinp_css");
    		        
                    var bt = document.createElement("img");    
                    bt.id = control.Input.id + "_CalendarBtn";
                    bt.setAttribute("impId", control.Input.id);
                    bt.alt = "";
                    bt.src = (control.Input.getAttribute("ClndImageSrc") ? control.Input.getAttribute("ClndImageSrc") : "PAT/Calendar/calendar.gif");

                    var pr = control.Input.parentNode;
                    var t = document.createElement("table");  
                    t.className = (control.Input.getAttribute("ClndTableCss") ? control.Input.getAttribute("ClndTableCss") : "def_emptytable_css");
                    var r = t.insertRow(0);
                    r.insertCell(0).appendChild(control.Input);
                    r.insertCell(1).appendChild(bt);

                    pr.appendChild(t);
                    bt.onclick = function(){if(!$get(this.getAttribute("impId")).disabled) return popUpCalendar(this, $get(this.getAttribute("impId")), 'MM/dd/yyyy'); };
                    control.Input.onclick = function(){if(!this.disabled) return popUpCalendar($get(this.id + "_CalendarBtn"), this, 'MM/dd/yyyy'); };
                }
                else
                    control.Input.onclick = function(){if(!this.disabled) return popUpCalendar(this, this, 'MM/dd/yyyy'); };
		    }
		}
	}

	self.FindRelated = function(inp)
	{
	    var List = inp.getAttribute("RowChangeNotifyList");
        var names  = (List != null && List != "" ? List.replace(/\s/g, "").split(",") : new Array());
        var res = new Array();
        for(var i=0; i<names.length; i++)
        {
            var parts = names[i].split("/");
    		var rex = new RegExp("^(.+)_" + self.name + "$", "i");
			if(parts.length > 1 && rex.exec(parts[0])) res.push({obj:parts[0], arg:parts[1]});
		}
        return res;
	}

	self.OnGetSingleRowRes = function(res) 
	{ 
	    if (res["errCode"] != null) return OnErr({obj: self, msg: res["errCode"]});
	    var tabData = res["tableRes"];

	    self.SetUpButtons();

	    self.table = tabData;

	    if (self.args.rowId == "-1" || self.table == null || self.table.rows == null || self.table.columns == null || self.table.rows.length < 1) {
	        self.ClearControls();
	        if (!self.alwaysEnabled) self.Disable(true);

	        for (var i = 0; i < self.controls.length; i++) {
	            var input = self.controls[i].Input;

	            if (self.controls[i].Type == fType.Text || self.controls[i].Type == fType.Textarea) RmvHandler(input, "blur", self.REEndEdit);
	            else if (self.controls[i].Type == fType.Check) RmvHandler(input, "click", self.REEndEdit);
	            else if (self.controls[i].Type == fType.Select) RmvHandler(input, "change", self.REEndEdit);
	            else if(self.controls[i].Type == fType.DDEx && objList[self.controls[i].id]) objList[self.controls[i].id].onValueChanged = null;
	            input.setAttribute("rowId", self.args.rowId);
	            input.setAttribute("dbname", input.id.replace("_" + self.name, ""));

	            if (eq(input.getAttribute("spellcheck"), "True") && (typeof (PNWSpeller) != "undefined") && (PNWSpeller != null))
	                SpellDecorate(input, "en", null, eq(input.getAttribute("nogrammarcheck"), "True"));
	        }
	        return;
	    }

	    for (var i = 0; i < self.controls.length; i++) {
	        var input = self.controls[i].Input;
	        var field = input.id.replace("_" + self.name, "");
	        var value = self.table.rows[0][field];

	        disableCtrl(input, false);
	        var opts = (input ? input.options : null);

	        if (input.id.indexOf("Button_") > 0)
	            continue;

	        value = (value == null ? "" : value);
	        if (input.getAttribute("EditType") == "Html")
	            input.innerHTML = value;
	        else
	            switch (self.controls[i].Type) {
	            case fType.Text: case fType.Textarea:
                    if (input.getAttribute("cnFormat")) value = ExecEx(input, "cnFormat", {obj: self, input: input, val: value});
	                input.value = value;
	                if (!self.UpdateButton) AddHandler(input, "blur", self.REEndEdit);
	                if (eq(input.getAttribute("spellcheck"), "True") && (typeof (PNWSpeller) != "undefined") && (PNWSpeller != null))
	                    SpellDecorate(input, "en", self.REEndEdit_noSpell, eq(input.getAttribute("nogrammarcheck"), "true"));
	                break;
	            case fType.tinyMCE:
	                tinyMCE.get(input.id).setContent(value);
	                //if (!self.UpdateButton) tinyMCE.get(input.id).onChange = function(params) {self.REEndEdit(input);}
	                break;
	            case fType.Datetime:
	                if(value != "")
	                    try { input.value = new Date(value).format("MM/dd/yyyy"); } catch (er) {input.value = "";}
	                else
	                    input.value = value;
	                if (!self.UpdateButton) AddHandler(input, "blur", self.REEndEdit);
	                break;
	            case fType.DDEx:
	                DDExRefresh(input.id, AddHash(self.args,"rowId",self.args.rowId), value);
	                if (!self.UpdateButton && objList[input.id]) objList[input.id].onValueChanged = function(params) {self.REEndEdit(params.obj.base);}
	                break;
	            case fType.Money:
	                input.value = FormatMoney(value);
	                if (!self.UpdateButton) AddHandler(input, "blur", self.REEndEdit);
	                break;
	            case fType.Select:
	                if (objList[input.id]) objList[input.id].initval = value;
	                for (var k = 0; k < self.controls[i].Related.length; k++) SetArgs(self.controls[i].Related[k].obj, Hash(self.controls[i].Related[k].arg, value));
	                if (!self.UpdateButton) AddHandler(input, "change", self.REEndEdit);
	                break;
	            case fType.Check:
	                input.checked = value;
	                if (!self.UpdateButton) AddHandler(input, "click", self.REEndEdit);
	                break;
	            default:
                    if (input.getAttribute("cnFormat")) value = ExecEx(input, "cnFormat", {obj: self, input: input, val: value});
	                try { input.value = value; } catch (ex) { }
	                try { SetText(input, value); } catch (ex) { }
	                break;
	        }
	        input.setAttribute("rowId", self.args.rowId);
	        input.setAttribute("dbname", field);
	        if(input.getAttribute("EditType") == "Html" || self.controls[i].Type == fType.Text || self.controls[i].Type == fType.Textarea)
	            input.setAttribute("oldval", text2inputvalue(input, value));
	        else
	            input.setAttribute("oldval", value);
	    }
	    for (var i = 0; i < self.controls.length; i++)
	        if (self.controls[i].Type == fType.Select) DDRefresh(self.controls[i].Input.id, {rowId: self.args.rowId});
	}

    self.Disable = function (dis)
        {
            for (var i = 0; i < self.controls.length; i++)
                disableCtrl(self.controls[i].Input, dis);

            if (self.InsertButton)   disableCtrl(self.InsertButton, dis);
            if (self.UpdateButton)   disableCtrl(self.UpdateButton, dis);
            if (self.ClearButton)    disableCtrl(self.ClearButton, dis);
            if (self.DeselectButton) disableCtrl(self.DeselectButton, dis);
        }

    self.ClearControls = function ()
        {
            for (var i = 0; i < self.controls.length; i++)
                ClearInput(self.controls[i].Input);                
        }

    self.REEndEdit_noSpell = function(inp) 
    {
		self.REEndEdit(inp, null, true);
    }
        
    self.REEndEdit = function(inp, evt, skipSpell) 
        {
			if(inp == null) return;

            var val = inp.value; 
            var type = fieldType(inp);
            if(type == fType.Check) val = (inp.checked ? 1 : 0);
            if(type == fType.DDEx)  val = DDExValue(inp.id);
            if(type == fType.tinyMCE) val = tinyMCE.get(inp.id).getContent();
            if(inp.value == "null") val = null;
            
            if(inp.getAttribute("oldval") != val)
            {
				if(inp.getAttribute("cnValidate") && inp.getAttribute("cnValidate") != "")
				{
				    var result = ExecEx(inp, "cnValidate", {obj: self, val: txt2js(val)});
                    if(result != null && (result.length == null && result == false || result.length && result.length > 0))
                    {  
                        if(result.length == null)
                            OnErr({obj: self, msg: "Incorrect " + inp.id.substr(0, inp.id.indexOf("_")), val: val});
                        else OnErr({obj: self, msg: result});
                        return inp.value = inp.getAttribute("oldval");
                    }  
				}
				ServerCall("SetData", self, {rowId: inp.getAttribute("rowId"), field: inp.getAttribute("dbname"), value: val, args: self.args, inputid: inp.id});
                // !!! Moved here from OnSetDataRes
                DataChangeNotify(self.DataChangeNotifyList, {act: "sre_setdata", rowId: inp.getAttribute("rowId")});
            }
            
	        if (!skipSpell && eq(inp.getAttribute("spellcheck"), "True") && (typeof(PNWSpeller) != "undefined") && (PNWSpeller != null))
				SpellDecorate(inp, "en", self.REEndEdit_noSpell, eq(inp.getAttribute("nogrammarcheck"), "True"));
        }

    self.OnSetDataRes = function (res)
        {
            var input = $get(res["args"]["inputid"]);
            var rowId = res["args"]["rowId"];
            var value = res["args"]["value"];
            if (res["errCode"] != null)
            {
				if (input.type == "checkbox")
                  input.checked = input.getAttribute("oldval");
                else
                  input.value = input.getAttribute("oldval");
              return OnErr({obj: self, msg: res["errCode"]});
            }

            input.setAttribute("oldval", text2inputvalue(input, value));

            ExecEx(input, "onSet", {obj: self, res: res});
        }

    self.REUpdateRow_ = function (btn, evt)
        {
            if(self.onValidateUpdate != null && !ExecEx(self, "onValidateUpdate", {obj: self})) return;
            self.REInsertRow(true);
        }

    self.REInsertRow_ = function (btn, evt)
        {
            if(self.onValidateInsert != null && !ExecEx(self, "onValidateInsert", {obj: self})) return;
            self.REInsertRow(false);
        }

        self.REInsertRow = function(updt) {
            var n = new Array();
            var o = new Array();

            for (var i = 0; i < self.controls.length; i++) {
                var input = self.controls[i].Input;

                if (input.id.indexOf("Button_") > 0)
                    continue;

                var val = "";
                var type = fieldType(input);
                if (type == fType.None)
                    continue;
                if (type == fType.Check) val = input.checked;
                else if (type == fType.DDEx) val = DDExValue(input.id);
                else if (type == fType.tinyMCE) val = tinyMCE.get(input.id).getContent();
                else if (input.value) val = input.value;

                if ((updt && input.getAttribute("oldval") != val) || !updt) {
                    if (input.getAttribute("cnValidate") && input.getAttribute("cnValidate") != "") {
                        var result = ExecEx(input, "cnValidate", { obj: self, val: txt2js(val) });
                        if (result != null && (result.length == null && result == false || result.length && result.length > 0)) {
                            if (result.length == null)
                                OnErr({ obj: self, msg: "Incorrect " + input.id.substr(0, input.id.indexOf("_")), val: val });
                            else OnErr({ obj: self, msg: result });
                            return input.focus();
                        }
                    }

                    o.push(val);
                    n.push(input.id.replace("_" + self.name, ""))
                }
            }

            if (n.length > 0) 
            {
                ServerCall("InsRow", self, { insNames: n, insArgs: o, rowId: updt ? self.args.rowId : null, args: self.args });
                // !!! Moved here from OnInsRowRes
                DataChangeNotify(self.DataChangeNotifyList, {act: "sre_insertrow"});
            }
        }

    self.OnInsRowRes = function (res)
    {
        if (res["errCode"] != null) return OnErr({obj: self, msg: res["errCode"]});

        if(!self.UpdateButton || self.args.rowId == "-1")
            if(!self.InsertButton || self.InsertButton && !eq(self.InsertButton.getAttribute("notClear"), "True"))     
                self.ClearControls();        
    }

    self.REClear = function ()
    {
        for (var i = 0; i < self.controls.length; i++)
        {
            var input = self.controls[i].Input;
            RmvHandler(input, "blur", self.REEndEdit);
            RmvHandler(input, "click", self.REEndEdit);
            ClearInput(input);
			if (eq(input.getAttribute("spellcheck"), "True") && (typeof(PNWSpeller) != "undefined") && (PNWSpeller != null))
				SpellDecorate(input, "en", self.REEndEdit_noSpell, eq(input.getAttribute("nogrammarcheck"), "True"));
        }
    }

    self.REDeselect = function ()
    {
        self.args.rowId = "-1";
        self.OnGetSingleRowRes(new Object());
    }
    
    self.IsLinked = function()
    {
        return self.args.rowId != "-1";
    }
    
    self.LoadData();
}





//-------------------------------------------------- DropDown --------------------------------------------------
//--------------------------------------------------------------------------------------------------------------

function DDInit(name, args, rowId)
{
    return PatObj_Init(PatObjType.DD, name, args, {rowId: rowId});
}

function DDRefresh(name, args)
{
    if(objList[name]) objList[name].LoadData(args);
}

function SetArgs(name, args)
{
    if(objList[name]) objList[name].args = AddHash(objList[name].args, args);
}

function DDSetValue(name, val)
{
    if(objList[name]) objList[name].SetValue(val);
}

function DDDisable(name, dis)
{
    if(objList[name]) objList[name].Disable(dis);
}

function DropDown(name, args, prms)
{
    var self = objList[name];
    if(self == null) return OnErr({msg: "Can't init object", val: name});

	self.initval = (prms.rowId != null ? prms.rowId : null);
    self.name = name;
    self.args = args;
    self.table = null;

	self.base =  $get(self.name);
	if (self.base == null) return;
	
    self.onServerCall = self.base.getAttribute("onServerCall");
    self.onServerRes = self.base.getAttribute("onServerRes");
    self.onDataLoaded = self.base.getAttribute("onDataLoaded");
    
	self.RowChangeNotifyList = self.base.getAttribute("RowChangeNotifyList");

    self.OnDataChangeNotification = function (params) 
        { 
            self.LoadData();
        }

    self.OnRowChangeNotification = function (params) 
        { 
            if (params != null)
            {
				if (params["rowId"] != null && params["rowidname"] != null)
					self.args = AddHash(self.args, params["rowidname"], params["rowId"]);
    				self.LoadData();
        	}
        }

    self.OnServiceRes = function (res)
    {
        switch(res["cmdCode"])
        {
            case "GetPDTable":   self.OnGetPDTableRes(res); break;
        }
    }

    self.LoadData = function (args)
        {
            if(args) AddHash(self.args, args);
            if (self.base.getAttribute("cnRelTableName")) 
                ServerCall("GetPDTable", self, {pdName: self.base.getAttribute("cnRelTableName"), args: self.args});
            else 
                self.OnGetPDTableRes(new Object());
        }


    self.OnGetPDTableRes = function (res)
        {
            if (res["errCode"] != null) return OnErr({obj: self, msg: res["errCode"]});
            self.table = res["tableRes"];
            
			var value = (self.initval != null ? self.initval : (self.base.value == "" ? self.base.getAttribute("cnDefVal") : self.base.value));
            self.initval = null;

            if(self.table) self.DbRowId = self.table.columns[0].name;
            AddHandler(self.base, "change", self.RowChangeNotify_);

            var cnRelSplitter  = (self.base.getAttribute("cnRelSplitter") ? self.base.getAttribute("cnRelSplitter") : ",");
            var cnRelNames  = (self.base.getAttribute("cnRelNames")  != null ? self.base.getAttribute("cnRelNames").split(cnRelSplitter) : new Array());
            var cnRelValues = (self.base.getAttribute("cnRelValues") != null ? self.base.getAttribute("cnRelValues").split(cnRelSplitter) : new Array());
            var cnRelColors = (self.base.getAttribute("cnRelColors") != null ? self.base.getAttribute("cnRelColors").split(cnRelSplitter) : new Array());
            var cnRelBackColor = self.base.getAttribute("cnRelBackColor");

            if(self.table && self.table.rows)
                for (var i=0; i < self.table.rows.length; i++)
                {
                    var len = cnRelNames.length != null ? cnRelNames.length : 0;
                    cnRelNames[len]  = self.table.rows[i][self.table.columns[1].name];
                    cnRelValues[len] = self.table.rows[i][self.table.columns[0].name];
                    if (cnRelBackColor != null) cnRelColors[len] = self.table.rows[i][cnRelBackColor];
                }
            
            self.base.innerHTML = "";
                for (var i = 0; i < cnRelNames.length; i++)
                {
                    var el = new Option(cnRelNames[i], cnRelValues[i]);
                    self.base.options.add(el);
                    if (cnRelColors != null && cnRelColors.length == cnRelNames.length)
                    {
                        el.style.backgroundColor = cnRelColors[i];
                        if(cnRelColors[i] == 'Black' || cnRelColors[i] == '#000000')
                        {
							el.style.color = "White";
                        }
                    }
                }
                
                var display = self.base.style.display;
                self.base.style.display = "none"; self.base.style.display = display; // tabs hack
                
                if (value != null && value.toString() != "") self.base.value = value;
			    if (self.base.value != value) self.base.selectedIndex = 0;
		    }

    self.RowChangeNotify_ = function (dd, evt)
        {
            RowChangeNotify(self.RowChangeNotifyList, {rowId: self.base.value != "" ? self.base.value : self.initval, rowidname: self.DbRowId});
        }

    self.SetValue = function (val)
        {
            self.initval = val;
            self.base.value = val;
            self.RowChangeNotify_();
        }

    self.Disable = function (dis)
        {
            self.base.disabled = dis;
        }
        
    self.LoadData();
}

//------------------------------------------------- DropDownEx -------------------------------------------------
//--------------------------------------------------------------------------------------------------------------

function DDExInit(name, args, defval)
{
    return PatObj_Init(PatObjType.DDEx, name, args, {defval: defval});
}


function DDExDel(name)
{
    if(!objList[name]) return;
    
    var self = objList[name];
    
    HidePopUp(self.div);
    RmvHandler(window, "resize", self.changePos);
    RmvHandler(document, "click", self.Hide);    
    
    delete objList[name];
}

function DDExRefresh(name, args, val)
{
    if(objList[name]) objList[name].Refresh(args, val);
}

function DDExDisable(name, dis)
{
    if(objList[name]) objList[name].Disable(dis);
}

function DDExValue(name)
{
    if(objList[name]) return objList[name].value;
}

function DDExVisual(name)
{
    if(objList[name]) return objList[name].input.innerHTML;
}

function DDExSetValue(name, val) // No notification raised on this. We should care to refresh related objects
{
    if(objList[name]) return objList[name].SetValue(val);
}

function DDExSelectAll(name, select)
{
    if(objList[name]) return objList[name].SelectAll(select);
}

function DDExClear(name)
{
    if(objList[name]) objList[name].Clear();
}

//DO NOT USE. Should be replaced with PatObj_GetArgs
function DDExGetArgs(name)
{
    if(objList[name]) return objList[name].args;
}

function DropDownEx(name, args, prms)
{
    var self = objList[name];
    if(self == null) return OnErr({msg: "Can't init object", val: name});

    self.name = name;
    self.args = args;
    self.table = null;

    self.base = $get(self.name);
    if(self.base == null) return;

    self.selOpts  = new Object();
    self.addOpts  = "";
    self.multSel  = eq(self.base.getAttribute("multSel"), "True");
    self.showVal  = eq(self.base.getAttribute("showVal"), "True");
    self.editable = eq(self.base.getAttribute("editable"), "True");
    self.opened   = eq(self.base.getAttribute("opened"), "True");
    self.selAll   = self.multSel && !eq(self.base.getAttribute("selAll"), "False");
    self.onlyDiv  = eq(self.base.getAttribute("onlyDiv"), "True");

	self.defVl = (prms.defval != null ? prms.defval : self.base.getAttribute("cnDefVal"));
	self.selectFirst = eq(self.base.getAttribute("selectFirst"), "True");
    self.value = null;
    self.dataLoaded = false;

    self.onServerCall = self.base.getAttribute("onServerCall");
    self.onServerRes = self.base.getAttribute("onServerRes");
    self.onDataLoaded = self.base.getAttribute("onDataLoaded");
        
    self.divCss = (self.base.getAttribute("divCss") ? self.base.getAttribute("divCss") : self.onlyDiv ? "def_ddex_od_css" : "def_ddex_div_css");
    self.optCss = (self.base.getAttribute("optCss") ? self.base.getAttribute("optCss") : "def_ddex_opt_css");
    self.spnCss = (self.base.getAttribute("spnCss") ? self.base.getAttribute("spnCss") : "def_ddex_spn_css");
    self.hovCss = (self.base.getAttribute("hovCss") ? self.base.getAttribute("hovCss") : "def_ddex_hov_css");
    self.selCss = (self.base.getAttribute("selCss") ? self.base.getAttribute("selCss") : "def_ddex_sel_css");
    self.ocnCss = (self.base.getAttribute("ocnCss") ? self.base.getAttribute("ocnCss") : "def_ddex_optcnt_css");
    self.saCss  = (self.base.getAttribute("saCss")  ? self.base.getAttribute("saCss")  : "def_ddex_sa_css");
    
    self.colID  = (self.base.getAttribute("colID")  ? self.base.getAttribute("colID")  : null);
    self.colName = (self.base.getAttribute("colName") ? self.base.getAttribute("colName") : null);

    self.divW = (self.base.getAttribute("divW")  ? self.base.getAttribute("divW")  : "150px");
    self.divH = self.base.getAttribute("divH");

    self.onValueChanged = self.base.getAttribute("onValueChanged");
    self.RowChangeNotifyList = self.base.getAttribute("RowChangeNotifyList");
    
    self.defSubscr = (self.base.getAttribute("defSubscr")? self.base.getAttribute("defSubscr") : "Please Select");
    self.input = document.createElement("div");
    self.input.className = (self.base.getAttribute("impCss")? self.base.getAttribute("impCss") : "def_ddex_imp_css");    
    self.input.innerHTML = self.defSubscr;
    if(self.base.getAttribute("impW")) self.input.style.width = self.base.getAttribute("impW");
    
    self.button = document.createElement("img");    
    self.button.className = (self.base.getAttribute("btnCss") ? self.base.getAttribute("btnCss") : "def_ddex_btn_css");    
    self.button.alt = "";
    self.button.src = patImg_DDEx;

    self.CntTableCss = (self.base.getAttribute("cntTableCss") ? self.base.getAttribute("cntTableCss") : "def_ddex_cnttable_css");    
    self.base.innerHTML = "<table class='" + self.CntTableCss + "'><tr><td></td><td></td></tr></table>";
    self.base.childNodes[0].childNodes[0].childNodes[0].childNodes[0].appendChild(self.input);
    self.base.childNodes[0].childNodes[0].childNodes[0].childNodes[1].appendChild(self.button);
    if(self.onlyDiv) self.base.childNodes[0].style.display = "none";

    self.div = document.createElement("div");
    self.div.className = self.divCss;
    self.base.appendChild(self.div);
    if(!self.onlyDiv) self.div.style.display = "none";

    self.sadiv = document.createElement("div");
    self.sadiv.className = self.saCss;
    if(self.selAll) self.div.appendChild(self.sadiv);

    self.ocndiv = document.createElement("div");
    self.ocndiv.style.minHeight = "10px";
    if(self.divW) self.ocndiv.style.minWidth = self.divW.toString();
    if(self.divH) self.ocndiv.style.maxHeight = self.divH.toString();
    self.ocndiv.className = self.ocnCss;
    self.div.appendChild(self.ocndiv);

    self.OnDataChangeNotification = function (params) 
        { 
            self.LoadData();
        }

    self.OnRowChangeNotification = function (params) 
        { 
            if(params != null && params["rowId"] != null && params["rowidname"] != null)
                self.args = AddHash(self.args, params["rowidname"], params["rowId"]);
	            self.LoadData();
        }

    self.OnServiceRes = function (res)
    {
        switch(res["cmdCode"])
        {
            case "GetPDTable":   self.OnGetPDTableRes(res); break;
        }
    }

    self.LoadData = function ()
        {
            var s = $get(self.name);
            if (s && s.getAttribute("cnRelTableName")) 
                ServerCall("GetPDTable", self, {pdName: s.getAttribute("cnRelTableName"), args: self.args});
            else 
                self.OnGetPDTableRes(new Object());
        }

    self.OnGetPDTableRes = function (res)
        {
            if (res["errCode"] != null) return OnErr({obj: self, msg: res["errCode"]});
            self.table = res["tableRes"];
            
            self.ClearVals();
            
            if(self.table) self.DbRowId = self.table.columns[0].name;

            var cnRelSplitter  = (self.base.getAttribute("cnRelSplitter") ? self.base.getAttribute("cnRelSplitter") : ",");
            var cnRelNames  = (self.base.getAttribute("cnRelNames")  != null ? self.base.getAttribute("cnRelNames").split(cnRelSplitter) : new Array());
            var cnRelValues = (self.base.getAttribute("cnRelValues") != null ? self.base.getAttribute("cnRelValues").split(cnRelSplitter) : new Array());
            var cnRelColors = (self.base.getAttribute("cnRelColors") != null ? self.base.getAttribute("cnRelColors").split(cnRelSplitter) : new Array());
            var cnRelBackColor = self.base.getAttribute("cnRelBackColor");

            if(self.table && self.table.rows)
                for (var i=0; i < self.table.rows.length; i++)
                {
                    var len = cnRelNames.length != null ? cnRelNames.length : 0;
                    cnRelNames[len]  = self.table.rows[i][self.colName ? self.colName : self.table.columns[1].name];
                    cnRelValues[len] = self.table.rows[i][self.colID   ? self.colID   : self.table.columns[0].name];
                    if (cnRelBackColor != null) cnRelColors[len] = self.table.rows[i][cnRelBackColor];
                }

            if(self.selAll) self.sadiv.innerHTML = "<a href='javascript:DDExSelectAll(\"" + self.name + "\", true)'>Select All</a>&nbsp;<a href='javascript:DDExSelectAll(\"" + self.name + "\", false)'>Unselect All</a>";
            self.ocndiv.innerHTML = "";
            var contain = false;
            for (var i = 0; i < cnRelNames.length; i++)
            {
                var opt = document.createElement("div");
                opt.className = self.optCss;
                if(cnRelNames[i]) opt.innerHTML = "<table><tr>" + (self.multSel ? "<td><input type='checkbox'/></td>" : "") + "<td><div class='" + self.spnCss + "'>" + Quote(cnRelNames[i]) + "</div></td></tr></table>";
                opt.setAttribute("value", cnRelValues[i]);
                opt.setAttribute("name", cnRelNames[i]);
                if(cnRelColors){opt.style.backgroundColor = cnRelColors[i];}
                AddHandler(opt, "mouseover", self.onOptMouseOver);
                AddHandler(opt, "mouseout", self.onOptMouseOut);
                AddHandler(opt, "click", self.onOptMouseClick);
                self.ocndiv.appendChild(opt);
                if (self.value == cnRelValues[i])
                {
                    contain = true;
                }
            }
            self.dataLoaded = true;
            if(self.newval || self.newval == '')
            {
                self.value = self.newval;
                self.newval = null;
            }
            else
                self.value = ((self.value && contain) ? self.value : (!self.multSel && self.defVl == null && cnRelValues.length > 0 && self.selectFirst) ? cnRelValues[0] : self.defVl);
            self.SetValue(self.value);
            if(self.opened) self.onInpMouseClick();
            //RowChangeNotify(self.RowChangeNotifyList, {rowId: self.value, rowidname: self.DbRowId});
        }
    
    self.Refresh = function (args, val)
    {
        if(args) AddHash(self.args, args);
        if(val || val == '') self.newval = val;
        objList[name].LoadData();
    }

    self.onInpMouseClick = function (obj, evt)
        {
            if(self.div.parentNode.tagName.toUpperCase() != "BODY") document.body.appendChild(self.div);
            //ShowPopUp(self.div, self.input);
            window.setTimeout(self.Show, 1);
            AddHandler(window, "resize", self.changePos);
            //if(evt) CancelBubbling(evt);
        }
    
    self.changePos = function (obj, evt)
        {
    	    SetDropDownPos(self.input, self.div);
        }

    self.onOptMouseClick = function (opt, evt)
        {
            if(!eq(opt.tagName, "div")) return;
            if(self.multSel)
            {
                var optText = opt.childNodes[0].childNodes[0].childNodes[0].childNodes[1].childNodes[0].innerHTML;
                if(opt.className == self.selCss) 
                {
                    opt.className = self.optCss; 
                    opt.innerHTML = "<table><tr><td><input type='checkbox' /></td><td><div class='" + self.spnCss + "'>" + optText + "</div></td></tr></table>"; // checked = true/false work bad with CancelBubbling
                    delete self.selOpts[opt.getAttribute("value")]; 
                }
                else
                {
                    self.selOpts[opt.getAttribute("value")] = opt;
                    opt.innerHTML = "<table><tr><td><input type='checkbox' checked/></td><td><div class='" + self.spnCss + "'>" + optText + "</div></td></tr></table>"; // checked = true/false work bad with CancelBubbling
                    opt.className = self.selCss;
                }
                CancelBubbling(evt);
            }
            else
            {
                if(opt.className == self.selCss) return;
                self.ClearVals();
                self.selOpts[opt.getAttribute("value")] = opt;
                opt.className = self.selCss;
            }
            self.CalcValues();
            RowChangeNotify(self.RowChangeNotifyList, {rowId: self.value, rowidname: self.DbRowId});
            ExecEx(self, "onValueChanged", {obj: self, val: self.value, opt: opt});
        }

    self.onOptMouseOver = function (opt, evt)
        {
            if(!eq(opt.tagName, "div")) return;
            if(opt.className == self.optCss) opt.className = self.hovCss;
        }

    self.onOptMouseOut = function (opt, evt)
        {
            if(!eq(opt.tagName, "div")) return;
            if(opt.className == self.hovCss) opt.className = self.optCss;
        }

    self.Disable = function (dis)
        {
            if(dis) RmvHandler(self.input,  "click", self.onInpMouseClick); else AddHandler(self.input,  "click", self.onInpMouseClick);
            if(dis) RmvHandler(self.button, "click", self.onInpMouseClick); else AddHandler(self.button, "click", self.onInpMouseClick);
        }
        
    self.ClearVals = function ()
        {
            self.addOpts = "";
            for (var id in self.selOpts) 
            { 
                self.selOpts[id].className = self.optCss; 
                if(self.multSel) self.selOpts[id].childNodes[0].childNodes[0].childNodes[0].childNodes[0].childNodes[0].checked = false;
                delete self.selOpts[id]; 
            }
        }

    self.CalcValues = function ()
        {
            var v = "", n = "";
            for (var id in self.selOpts) { v += id + ","; n += self.selOpts[id].getAttribute("name") + ", "; }
            v = (v.length > 1 ? v.substring(0, v.length - 1) : "");
            self.value = v + (v != "" && self.addOpts != "" ? "," : "") + self.addOpts;
            n = Quote(n.length > 2 ? n.substring(0, n.length - 2) : "");
            n = n + (n != "" && self.addOpts != "" ? ", " : "") + self.addOpts;
            if(n == "") n = self.defSubscr;
            if(self.showVal)
                self.input.innerHTML = self.ClearValue(self.value);
            else
                self.input.innerHTML = self.ClearValue(n);
            for (var id in self.selOpts) {self.input.style.backgroundColor = self.selOpts[id].style.backgroundColor; return;}
        }

    self.Clear = function ()
        {
            self.ClearVals();
            self.CalcValues();
        }

    self.SetValue = function (val)    
        {
            self.ClearVals();
            self.value = val;
            if(!self.dataLoaded) 
            {
                self.newval = val;
                return;
            }
            var vals  = (val != null && val != "" ? val.toString().replace(/\s/g, "").split(",") : new Array());
            var op = null;
            
            for(var i=0; i<vals.length; i++)
            {
                for(var j=0; j<self.ocndiv.childNodes.length; j++)
                {
                    op = self.ocndiv.childNodes[j];
                    if(op.getAttribute("value") == vals[i])
                    {
                        self.selOpts[vals[i]] = op;
                        if(self.multSel) op.childNodes[0].childNodes[0].childNodes[0].childNodes[0].childNodes[0].checked = true;
                        op.className = self.selCss;
                    }
                }
                if(self.selOpts[vals[i]] == null) self.addOpts = self.addOpts + (self.addOpts != "" ? ", " : "") + vals[i];
            }
            if(self.editable) self.input.innerHTML = self.ClearValue(val);
            self.CalcValues();
        }
        
    self.ClearValue = function (val)    
        {
            if(!val) return "";
            return val.replace(/<[^>^<]*>/g, "");
        }

    self.LoadValue = function ()    
        {
            self.SetValue(self.ClearValue(self.input.innerHTML));        
            RowChangeNotify(self.RowChangeNotifyList, {rowId: self.value, rowidname: self.DbRowId});
            ExecEx(self, "onValueChanged", {obj: self, val: self.value, opt: null});
        }

    self.SelectAll = function (select)    
        {
            self.ClearVals();

            for(var j=0; select && j<self.ocndiv.childNodes.length; j++)
            {
                var op = self.ocndiv.childNodes[j];
                self.selOpts[op.getAttribute("value")] = op;
                if(self.multSel) op.childNodes[0].childNodes[0].childNodes[0].childNodes[0].childNodes[0].checked = select;
                op.className = self.selCss;
            }
            self.CalcValues();
            RowChangeNotify(self.RowChangeNotifyList, {rowId: self.value, rowidname: self.DbRowId});
            ExecEx(self, "onValueChanged", {obj: self, val: self.value, opt: null});
        }

    self.Hide = function (fierEvt)
        {
            if(self.div.style.display == "none") return;
            self.div.style.display = "none";
            if(fierEvt != false) ExecEx(self.base, "onHide", {obj: self, val: self.base.value});
        }

    self.Show = function ()
        {
            //OnShowPopUp(self.div);
        
            if(self.div.parentNode.tagName.toUpperCase() != "BODY")  document.body.appendChild(self.div);
	        self.div.style.display = "";
	        SetDropDownPos(self.input, self.div);
        }

    if(!self.onlyDiv)
    {
        AddHandler(document, "click", self.Hide);
        if(self.editable) AddHandler(self.input, "blur", self.LoadValue);
        AddHandler(self.input,  "click", self.onInpMouseClick);
        AddHandler(self.button, "click", self.onInpMouseClick);
    }
    self.LoadData();
}


//------------------------------------------------- AutoComplete -------------------------------------------------
//--------------------------------------------------------------------------------------------------------------

function AutoCompleteInit(name, args, prms)
{
    return PatObj_Init(PatObjType.ACmplt, name, args, prms);
}

function AutoCompleteDel(name)
{
    if(!objList[name]) return;
    
    var self = objList[name];

    self.Hide(false);
    RmvHandler(document, "click", self.Hide);
    RmvHandler(self.base, "keydown", self.onKeyPress);
    RmvHandler(self.base, "focus", self.onFocus);
    
    //objList[name].div.parentNode.removeChild(objList[name].div);
    
    delete objList[name];
}

function AutoCompleteValue(name)
{
    if(objList[name]) return objList[name].base.value;
}

function AutoCompleteSelValue(name)
{
    if(objList[name]) return objList[name].selValue;
}

function AutoCompleteHide(name, fierEvt)
{
    if(objList[name]) return objList[name].Hide(fierEvt);
}

function AutoCompleteDisable(name, dis)
{
    if(objList[name]) objList[name].Disable(dis);
}

function AutoComplete(name, args, prms)
{
    var self = objList[name];
    if(self == null) return OnErr({msg: "Can't init object", val: name});

    self.name = name;
    self.args = args;
    self.table = null;

    self.base = $get(self.name);
    if(self.base == null) return;

    self.onServerCall = self.base.getAttribute("onServerCall");
    self.onServerRes = self.base.getAttribute("onServerRes");
    self.onDataLoaded = self.base.getAttribute("onDataLoaded");

    self.divCss = (self.base.getAttribute("divCss") ? self.base.getAttribute("divCss") : "def_ddex_div_css");
    self.optCss = (self.base.getAttribute("optCss") ? self.base.getAttribute("optCss") : "def_ddex_opt_css");
    self.spnCss = (self.base.getAttribute("spnCss") ? self.base.getAttribute("spnCss") : "def_ddex_spn_css");
    self.hovCss = (self.base.getAttribute("hovCss") ? self.base.getAttribute("hovCss") : "def_ddex_hov_css");
    self.ocnCss = (self.base.getAttribute("ocnCss") ? self.base.getAttribute("ocnCss") : "def_ddex_optcnt_css");
    self.saCss  = (self.base.getAttribute("saCss")  ? self.base.getAttribute("saCss")  : "def_ddex_sa_css");
            
    self.cnMaxOpts = (self.base.getAttribute("cnMaxOpts") ? self.base.getAttribute("cnMaxOpts") : null);        

    self.cnDelay = (self.base.getAttribute("cnDelay") ? self.base.getAttribute("cnDelay") : 300);        
    
    self.divW = (self.base.getAttribute("divW") ? self.base.getAttribute("divW") : "150px");
    self.divH = self.base.getAttribute("divH");

    self.base.setAttribute("autocomplete","off");
    
    self.div = document.createElement("div");
    self.div.className = self.divCss;
    self.div.style.display = "none";
    self.base.parentNode.appendChild(self.div);

    self.sadiv = document.createElement("div");
    self.sadiv.className = self.saCss;
    self.div.appendChild(self.sadiv);

    self.ocndiv = document.createElement("div");
    self.ocndiv.style.minHeight = "10px";
    if(self.divW) self.ocndiv.style.minWidth = self.divW.toString();
    if(self.divH) self.ocndiv.style.maxHeight = self.divH.toString();
    self.ocndiv.className = self.ocnCss;
    self.div.appendChild(self.ocndiv);

    self.RowChangeNotifyList = self.base.getAttribute("RowChangeNotifyList"); //only for selected values from list now

    self.cnRelTableName = self.base.getAttribute("cnRelTableName");
    self.cnFilter = self.base.getAttribute("cnFilter") ? self.base.getAttribute("cnFilter") : "filter";
    self.cnColumn = self.base.getAttribute("cnColumn");
    self.cnVColumn = self.base.getAttribute("cnVColumn");
    self.selValue = ""; // have a sence only if cnVColumn is setted
    
    self.timer = null;
    self.opts = new Array();
    self.aOptInsex = -1;

    self.OnServiceRes = function (res)
    {
        switch(res["cmdCode"])
        {
            case "GetPDTable":   self.OnGetPDTableRes(res); break;
        }
    }

    self.Disable = function (dis)
    {
        self.base.disabled = dis;
    }

    self.LoadData = function ()
        {
            self.args[self.cnFilter] = self.base.value;
             
            if (self.cnRelTableName) 
                ServerCall("GetPDTable", self, {pdName: self.cnRelTableName, pagesize: self.cnMaxOpts, args: self.args});
            else 
                self.OnGetPDTableRes(new Object());
        }
    self.OnRowChangeNotification = function(params) {
        if (params != null && params["rowId"] != null && params["rowidname"] != null)
            self.args = AddHash(self.args, params["rowidname"], params["rowId"]);
    }

    self.OnGetPDTableRes = function (res)
        {
            if (res["errCode"] != null) return OnErr({obj: self, msg: res["errCode"]});
            self.table = res["tableRes"];
            
            self.selValue = "";
            
            var cnRelSplitter  = (self.base.getAttribute("cnRelSplitter") ? self.base.getAttribute("cnRelSplitter") : ",");
            var cnRelNames  = (self.base.getAttribute("cnRelNames")  != null ? self.base.getAttribute("cnRelNames").split(cnRelSplitter) : new Array());
            var cnRelValues = (self.base.getAttribute("cnRelValues") != null ? self.base.getAttribute("cnRelValues").split(cnRelSplitter) : new Array());
            var cnRelColors = (self.base.getAttribute("cnRelColors") != null ? self.base.getAttribute("cnRelColors").split(cnRelSplitter) : new Array());
            var cnRelBackColor = self.base.getAttribute("cnRelBackColor");

            if(self.table && self.table.rows)
                for (var i=0; i < self.table.rows.length; i++)
                {
                    var len = cnRelNames.length != null ? cnRelNames.length : 0;
                    var cname = (self.cnColumn ? self.cnColumn : self.table.columns[0].name);
                    cnRelNames[len]  = self.table.rows[i][cname];
                    if(self.cnVColumn) cnRelValues[len]  = self.table.rows[i][self.cnVColumn];
                    if (cnRelBackColor != null) cnRelColors[len] = self.table.rows[i][cnRelBackColor];
                }

            self.ocndiv.innerHTML = "";
            self.opts.length = 0;
            self.aOptInsex = -1;
            for (var i = 0, j = 0; i < cnRelNames.length; i++)
            {
                if(!cnRelNames[i] || cnRelNames[i] == "") continue;
                var opt = document.createElement("div");
                opt.className = self.optCss;
                opt.setAttribute("index", j++);
                opt.innerHTML = "<span class='" + self.spnCss + "' value='" + (cnRelValues[i] ? Quote(cnRelValues[i]) : "") + "'>" + Quote(cnRelNames[i]) + "</span>";
                if(Quote(cnRelNames[i]) == self.base.value) self.selValue = Quote(cnRelValues[i]);
                opt.setAttribute("name", cnRelNames[i]);
                if(cnRelColors){opt.style.backgroundColor = cnRelColors[i];}
                AddHandler(opt, "mouseover", self.onOptMouseOver);
                AddHandler(opt, "mouseout", self.onOptMouseOut);
                AddHandler(opt, "click", self.onOptMouseClick);
                self.ocndiv.appendChild(opt);
                self.opts.push(opt);
            }
            
            if(self.opts.length > 0)
            {
                self.Show();
                AddHandler(window, "resize", self.changePos);
            }
            else
                self.Hide(false);
        }

    self.onKeyPress = function (obj, evt)
        {
            switch(evt.keyCode)
            {
                case BOTTOM_KEY_CODE:
                    if(self.div.style.display == "none") break;
                    self.SetActiveOpt(self.aOptInsex + 1);
                    return;
                case TOP_KEY_CODE:
                    self.SetActiveOpt(self.aOptInsex - 1);
                    return;
                case ENTER_KEY_CODE: case TAB_KEY_CODE:
                    self.Close();
                    return;
                case ESC_KEY_CODE:
                    self.Hide(false);
                    return;
            }
	        if(self.timer) window.clearTimeout(self.timer);
	        self.timer = window.setTimeout(self.LoadData, self.cnDelay);
        }
        
    self.onFocus = function (obj, evt)
        {
	        if(self.timer) window.clearTimeout(self.timer);
	        self.timer = window.setTimeout(self.LoadData, self.cnDelay);
        }
    
    self.onBaseClick = function (obj, evt)
        {
            CancelBubbling(evt);
        }
    
    self.changePos = function (obj, evt)
        {
    	    SetDropDownPos(self.base, self.div);
        }

    self.onOptMouseClick = function (opt, evt)
        {
            if(!eq(opt.tagName, "div")) return;
            self.Close();
        }

    self.Close = function ()
        {
            if(self.aOptInsex >= 0 && self.aOptInsex < self.opts.length)
            {
                self.base.value = self.opts[self.aOptInsex].firstChild.innerHTML;
                self.selValue = self.opts[self.aOptInsex].firstChild.getAttribute("value");
                ExecEx(self.base, "onSelected", {obj: self, val: self.base.value, selval: self.selValue});
                RowChangeNotify(self.RowChangeNotifyList, {rowId: (self.selValue != "" ? self.selValue : self.base.value), rowidname: null});
            }
            self.Hide();
        }

    self.onOptMouseOver = function (opt, evt)
        {
            if(!eq(opt.tagName, "div")) return;
            self.SetActiveOpt(opt.getAttribute("index"));
        }

    self.onOptMouseOut = function (opt, evt)
        {
            if(!eq(opt.tagName, "div")) return;
            self.SetActiveOpt();
        }

    self.SetActiveOpt = function (index)
        {
            if(self.opts.length == 0) return;
            if(self.aOptInsex >= 0 && self.aOptInsex < self.opts.length)self.opts[self.aOptInsex].className = self.optCss;
            self.aOptInsex = -1;

            if(index == null) return;
            if(index < 0) index = self.opts.length - 1;
            if(index >= self.opts.length) index = 0;
            
            self.aOptInsex = index;
            self.opts[index].className = self.hovCss;
        }

    self.Hide = function (fierEvt)
        {
            if(self.div.style.display == "none") return;
            self.div.style.display = "none";
            if(fierEvt != false) ExecEx(self.base, "onHide", {obj: self, val: self.base.value});
        }

    self.Show = function ()
        {
            //OnShowPopUp(self.div);

            if(self.div.parentNode.tagName.toUpperCase() != "BODY")  document.body.appendChild(self.div);
	        self.div.style.display = "";
	        SetDropDownPos(self.base, self.div);
        }

    AddHandler(document, "click", self.Hide);
    AddHandler(self.base, "keydown", self.onKeyPress);
    AddHandler(self.base, "focus", self.onFocus);
    AddHandler(self.base, "click", self.onBaseClick);
}

//--------------------------------------------------- TabsObj --------------------------------------------------
//--------------------------------------------------------------------------------------------------------------

function TabsInit(name, selected, loader)
{
    return PatObj_Init(PatObjType.Tabs, name, null, {selected: selected, loader: loader});
}

function TabsSetSelected(name, tabname)
{
    if(objList[name]) objList[name].SetSelected(tabname);
}

function TabsDisable(name, tabname)
{
    if(objList[name]) objList[name].Disable(tabname);
}

function TabsHide(name, hide)
{
    if(objList[name]) objList[name].Hide(hide);
}

function TabsHideTab(name, tabname, hide)
{
    if(objList[name]) objList[name].HideTab(tabname, hide);
}

function TabsSetTabCaption(name, tabname, caption)
{
    if(objList[name]) objList[name].SetTabCaption(name, tabname, caption);
}

function TabsGetSelected(name)
{
    if(objList[name]) return objList[name].selected;
    return null; 
}

function TabsObj(name, args, prms)
{
    var self = objList[name];
    if(self == null) return OnErr({msg: "Can't init object", val: name});

    self.name = name;
    self.selected = prms.selected;
	self.tabsContainer = $get(name + "_TabsContainer");
	self.tabsMenu = $get(name + "_TabsMenu");	
	
	if(self.tabsContainer == null || self.tabsMenu == null || self.tabsContainer.childNodes.length == 0) return;

	self.tabCss = self.tabsMenu.getAttribute("tabCss");
	self.atabCss = self.tabsMenu.getAttribute("atabCss");
	self.dtabCss = self.tabsMenu.getAttribute("dtabCss");
	self.htabCss = self.tabsMenu.getAttribute("htabCss");
	
	self.outSpCss = self.tabsMenu.getAttribute("outSpCss");
	self.aoutSpCss = self.tabsMenu.getAttribute("aoutSpCss");
	self.doutSpCss = self.tabsMenu.getAttribute("doutSpCss");
	self.houtSpCss = self.tabsMenu.getAttribute("houtSpCss");

	self.inSpCss = self.tabsMenu.getAttribute("inSpCss");
	self.ainSpCss = self.tabsMenu.getAttribute("ainSpCss");
	self.dinSpCss = self.tabsMenu.getAttribute("dinSpCss");
	self.hinSpCss = self.tabsMenu.getAttribute("hinSpCss");

    self.tabs = new Object();
    self.itms = new Object();

    self.LoadObj = function () 
        { 
	        for(var i=0; i<self.tabsContainer.childNodes.length; i++)
	        {
	            if(self.tabsContainer.childNodes[i].getAttribute == null || self.tabsContainer.childNodes[i].getAttribute("name") == null || self.tabsContainer.childNodes[i].style.display == "none") continue;
	            var name = self.tabsContainer.childNodes[i].getAttribute("name");
	            if(self.selected == null) self.selected = name;
	            self.tabs[name] = self.tabsContainer.childNodes[i];
                if(name != self.selected) self.tabs[name].style.display = "none";

                var ul = document.createElement("ul");
                var lnk = document.createElement("li");
                var outSp = document.createElement("span");
                var inSp = document.createElement("span");
                AddHandler(lnk, "click", self.OnItemClick);
                AddHandler(lnk, "mouseover", self.OnItemMOver);
                AddHandler(lnk, "mouseout", self.OnItemMOut);
                lnk.setAttribute("name", name);
                inSp.innerHTML = name;
                lnk.className = (name != self.selected ? self.tabCss : self.atabCss);
                outSp.className = (name != self.selected ? self.outSpCss : self.aoutSpCss);
                inSp.className = (name != self.selected ? self.inSpCss : self.ainSpCss);
                ul.appendChild(lnk);
                lnk.appendChild(outSp);
                outSp.appendChild(inSp);
                self.tabsMenu.appendChild(ul);
                self.itms[name] = lnk;
	        }
	    }

    self.SetSelected = function (tabname) 
        { 
            if(self.selected == tabname || self.itms[tabname].className == self.dtabCss) return;
            self.tabs[self.selected].style.display = "none";
            self.itms[self.selected].className = self.tabCss;
            self.itms[self.selected].firstChild.className = self.outSpCss;
            self.itms[self.selected].firstChild.firstChild.className = self.inSpCss;
            self.selected = tabname;
            self.tabs[self.selected].style.display = "";
            self.itms[self.selected].className = self.atabCss;
            self.itms[self.selected].firstChild.className = self.aoutSpCss;
            self.itms[self.selected].firstChild.firstChild.className = self.ainSpCss;
            if(self.tabs[self.selected].getAttribute("onSelect"))
                ExecEx(self.tabs[self.selected], "onSelect", {obj: self, tabname: tabname});
        }

    self.SetTabCaption = function (name, tabname, caption)
        {
            self.itms[tabname].firstChild.firstChild.innerHTML = caption;
        }

    self.Disable = function (tabname) 
        { 
            self.itms[tabname].className = self.dtabCss;
            self.itms[tabname].firstChild.className = self.doutSpCss;
            self.itms[tabname].firstChild.firstChild.className = self.dinSpCss;
        }

    self.Hide = function (hide) 
        { 
            self.tabsMenu.style.display = (hide ? "none" : "");
        }
        
    self.HideTab = function (tabname, hide)
        {
            self.itms[tabname].style.display = (hide ? "none" : "");
            if(hide && self.itms[tabname].className == self.atabCss)
                for (var tname in self.itms)
                    if(self.itms[tname].style.display != "none" && self.itms[tname].className != self.dtabCss)
                        return self.SetSelected(tname);
        }
        
    self.OnItemClick = function (lnk, evt) 
        {
            if(!eq(lnk.tagName, "li")) return;
            self.SetSelected(lnk.getAttribute("name"));
        }
        
    self.OnItemMOver = function (lnk, evt) 
        {
            if(!eq(lnk.tagName, "li")) return;
            if(lnk.className != self.atabCss && lnk.className != self.dtabCss)
            {
                lnk.className = self.htabCss;
                lnk.firstChild.className = self.houtSpCss;
                lnk.firstChild.firstChild.className = self.hinSpCss;
            }
        }
        
    self.OnItemMOut = function (lnk, evt) 
        {
            if(!eq(lnk.tagName, "li")) return;
            if(lnk.className != self.atabCss && lnk.className != self.dtabCss)
            {
                lnk.className = self.tabCss;
                lnk.firstChild.className = self.outSpCss;
                lnk.firstChild.firstChild.className = self.inSpCss;
            }
        }

    self.LoadObj();
}


//--------------------------------------------------- PopUpObj --------------------------------------------------
//--------------------------------------------------------------------------------------------------------------

function PopUpInit(name, args, prms)
{
    return PatObj_Init(PatObjType.PopUp, name, args, prms);
}

function PopUpShow(name, show)
{
    if(objList[name]) objList[name].Show(show);
}

function PopUpShowWithFrame(name, url)
{
    if(objList[name]) objList[name].ShowWithFrame(url);
}

function PopUpObj(name, args, prms)
{
    var self = objList[name];
    if(self == null) return OnErr({msg: "Can't init object", val: name});

    self.name = name;
	self.body = $get(name + "_PopUp");
	if(!self.body) { OnErr({obj: self, msg: "Pop-up init Error"}); return; }

    self.modaldiv = document.createElement("div");
    self.body.parentNode.appendChild(self.modaldiv);
    self.modaldiv.className = (self.body.getAttribute("ModalDivCss") ? self.body.getAttribute("ModalDivCss") : "def_popup_modaldiv_css");
	self.modaldiv.style.display = "none";
    
    self.bodybasediv = document.createElement("div");
    self.body.parentNode.appendChild(self.bodybasediv);

    self.bodybasediv.innerHTML = "<table style='width:100%; height:100%'><tr><td style='vertical-align:middle; text-align:center;' id='" + self.name + "_PopUp_baseTd'></td></tr></table>";  
    self.bodybasediv.className = (self.body.getAttribute("ModalBasDivCss") ? self.body.getAttribute("ModalBasDivCss") : "def_popup_basediv_css");
	self.bodybasediv.style.display = "none";
	
	self.onShow = (self.body.getAttribute("OnShow") ? self.body.getAttribute("OnShow") : null);
	self.onHide = (self.body.getAttribute("OnHide") ? self.body.getAttribute("OnHide") : null);

	self.disEsc = (self.body.getAttribute("DisEsc") ? eq(self.body.getAttribute("DisEsc"), "TRUE") : false);
	
	if(eq(self.body.getAttribute("Style3d"), "True"))
	{
	    var Caption = (self.body.getAttribute("Caption3d") ? "<span style='float:left; margin-left:5px;'>" + self.body.getAttribute("Caption3d") + "</span>" : "")
	    var Close = (self.body.getAttribute("Close3d") != "False" ? "<span style='float:right; cursor:pointer; margin-right:5px;' onclick=\"PopUpShow('" + self.name + "', false);\">x</span>" : "")
	    $get(name + "_PopUp_baseTd").innerHTML = "<center><table class='dialog-3d'><tr><th class='caption-left' /><th class='caption-center'>" + Caption + Close + "</th><th class='caption-right' /></tr>" +
                              "<tr class='body-row'><td class='body-left' /><td class='body-placeholder' id='" + name + "_PopUp_base3dTd'>" + 
                              "</td><td class='body-right' /></tr><tr><td class='bottom-left' /><td class='bottom-center' /><td class='bottom-right' /></tr></table></center>";
        self.content = $get(name + "_PopUp_base3dTd");
	}
	else
        self.content = $get(name + "_PopUp_baseTd");
        
    self.content.appendChild(self.body);
    
    self.Show = function (show) 
    { 
        if(show) patPopUpList.push(self); else patPopUpList.pop();
        self.modaldiv.style.display = (show ? "inline" : "none");
        self.bodybasediv.style.display = (show ? "inline" : "none"); 
        if (show) 
        {
            ExecEx(self, "onShow", {obj: self});
        }
        else
        {
            ExecEx(self, "onHide", {obj: self});
            if(self.iframe) self.content.innerHTML = "";
        }
	}

    self.ShowWithFrame = function (url) 
    { 
        self.content.innerHTML = "<iframe id='" + name + "_Frame' src='' style='" + self.body.getAttribute("style") + "' frameborder='0' scrolling='no'></iframe>";
        self.iframe = $get(name + "_Frame");
        self.iframe.src = url;
        self.Show(true);
    }
}

// to provide dissapear top pop-up on Esc button
var patPopUpList = new Array();
function hideTopPopUp()
{
    if(patPopUpList.length > 0 && !patPopUpList[patPopUpList.length-1].disEsc) patPopUpList[patPopUpList.length-1].Show(false);
}
function hideTopPopUpOnEsc(inp, evt)
{
    if(evt.keyCode == ESC_KEY_CODE) hideTopPopUp();
}
window.setTimeout(function(){AddHandler(document, "keydown", hideTopPopUpOnEsc);}, 100);


//----------------------------------------------- Load Indicator ----------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------------

function ProgressInit(name, prms)
{
   Progress = new PATProgress(name, prms);   
}

function PATProgress(name, prms)
{
    if(prms == null) prms = new Object();
    var self = this;
   
   self.PrgrCss      = (prms.PrgrCss == null ? "def_progress_css" : prms.PrgrCss);
   self.PrgrOnShow   = prms.PrgrOnShow;
   self.PrgrCstShow  = prms.PrgrCstShow;
   self.PrgrObj      = prms.obj;
   self.PrgrDisable  = prms.PrgrDisable;
   self.PrgrCoverDiv = prms.PrgrCoverDiv;
   self.PrgrCoverDivCss    = (prms.PrgrCoverDivCss == null ? "def_coverdiv_css" : prms.PrgrCoverDivCss);
   self.PrgrCoverDivImgCss = (prms.PrgrCoverDivImgCss == null ? "def_coverdivimg_css" : prms.PrgrCoverDivImgCss);
   self.PrgrCoverDivImg    = (prms.PrgrCoverDivImg == null ? patImg_Prgr : prms.PrgrCoverDivImg);
   self.PrgrCoverDivTxt    = (prms.PrgrCoverDivTxt == null ? "please wait..." : prms.PrgrCoverDivTxt);
   
   if(null != name)   
   {
      self.Prgr = document.getElementById(name);
      if(self.Prgr) self.Prgr.className = self.PrgrCss;
        
      self.Show = function(show) 
      {
          ExecEx(self, "PrgrOnShow", {obj: self, show: show, prgObj: self.PrgrObj});
          if(self.PrgrCstShow) ExecEx(self, "PrgrCstShow", {obj: self, show: show, prgObj: self.PrgrObj});
          else if (self.Prgr) self.Prgr.style.visibility = (show ? "visible" : "hidden");
          else if (self.PrgrDisable && self.PrgrObj && self.PrgrObj.Disable) self.PrgrObj.Disable(show);
          else if (self.PrgrCoverDiv) self.ShowCover(show);
      }
      
      self.CreateCover = function()
      {
        if(!docLoaded) return;
        self.DivToCover = document.getElementById(self.PrgrCoverDiv);
        if(self.DivToCover == null) return;

        self.DivToShow = document.createElement("div");
        self.DivToShow.className = self.PrgrCoverDivCss;
        self.DivToShow.style.display = "none";
        //self.DivToShow.style.position = "absolute";
        document.body.appendChild(self.DivToShow);

        self.ImgToShow = document.createElement("div");
        self.ImgToShow.className = self.PrgrCoverDivImgCss;
        self.ImgToShow.style.display = "none";
        self.ImgToShow.style.position = "absolute";
        self.ImgToShow.innerHTML = "<table><tr><td valign='middle'><img src='" + self.PrgrCoverDivImg + "'></td><td valign='middle' style='padding-left:10px;'>" + self.PrgrCoverDivTxt + "</td></tr></table>";
        document.body.appendChild(self.ImgToShow);
      }
      
      self.ShowCover = function(show)
      {
        if(self.DivToShow == null) self.CreateCover();
        if(self.DivToCover == null || self.DivToShow == null) return;
        
        var rect = GetRect(self.DivToCover);
        self.DivToShow.style.height = rect.Height + "px"; 
        self.DivToShow.style.width  = rect.Width + "px";

        self.DivToShow.style.left = rect.x + "px"; 
        self.DivToShow.style.top  = rect.y + "px";
        
        
        self.ImgToShow.style.left = rect.x + rect.Width/2 - 40 + "px"; 
        self.ImgToShow.style.top  = rect.y + rect.Height/2 - 10 + "px";
        
        self.DivToShow.style.display = (show ? "" : "none");
        self.ImgToShow.style.display = (show ? "" : "none");
      }
   }
   self.Show(false);
}

//----------------------------------------------- Export ------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------------
function ExportTo(objName, format, map)
{
	var sParams = "export="+format+"&obj=" + objName;
	var objArgs = PatObj_GetArgs(objName);
	if (typeof(objArgs) != "undefined")
		sParams += "&args=" + escape(Quote(JSON2.stringify(objArgs)));
	if (typeof(map) != "undefined")
		sParams += "&map=" + map;
	window.open('PAT/Export/Export.aspx?' + sParams);
}

//---------------------------------------------- Pivot Table -------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------

function PVTableEditor(name, args, xsl)
{
    var self = this;

    self.name = name;
    self.args = args;
    self.xsl = "" + xsl;
    self.OnRowSelect = function() {};
    
    var tblResult = null;
    var tblFiltered = null;
    var tblFilterBy = null;
 
    var Init = function()
    {
        if(self.args == null)
            self.args = new Object();
        
        if(self.args["pivotTable"] == null)
            self.args["pivotTable"] = self.name;
        
        tblFiltered = $get(self.name + "Filtered");
        if(tblFiltered == null)
            throw "Pivot table:\r\nFiltered table should be declared!";
        
        tblFilterBy = $get(self.name + "FilterBy");
        if(tblFilterBy == null)
            throw "Pivot table:\r\nFilterBy table should be declared!";
        
        tblResult = $get(self.name + "Result")
        if(tblResult == null)
            throw "Pivot table:\r\nResult table should be declared!";
            
        TableInit(tblFilterBy.id, self.args);
        TableInit(tblResult.id, self.args);
        TableInit(tblFiltered.id, self.args);
    }
  
    var activeField = "";
    self.OnFilterByRowChanged = function(p)
    {
        var name = p.obj.name;
        var dbid = p.curRowId;
        if(arguments.length > 0 && activeField != dbid)
        {
            var params = CloneHash(self.args);
            
            AddHash(params, "filterby", dbid);
            TableRefresh( self.name + "Result", params);
            TableRefresh( self.name + "FilterBy", params);
            TableRefresh( self.name + "Filtered", params);
            activeField = dbid;
        }
    }
    self.SelectedRender = function(p)
    {
        var chk = null;
        if(p.cell.firstChild != null)
            chk = p.cell.firstChild;
        else
        {    
            chk = document.createElement("INPUT");
            chk.type = "checkbox";
            p.cell.appendChild(chk);
        }

        chk.checked = p.val;
        chk.setAttribute("table", p.obj.name);
        var rowId = -1;
        try{rowId = p.obj.table.rows[p.row.rowIndex-1][p.obj.DbRowId];}catch(e){;}
        
        chk.style.display = (rowId == null || rowId == -1)? "none": "inline";
        chk.setAttribute("rowId", rowId);
        
        AddHandler(chk, "click", DoChk);
    }
    self.OnFilterByEnabled = function(p)
    {
        if(p.row.getAttribute("arranged")) return;
        if( p.val == "0")
            p.row.style.color = "gray";
        else
            p.row.style.color = "";
    }
    self.OnDeleteFilter = function(p)
    {
        if(p.cmdCode == "DelRow") {
            TableRefresh( self.name + "Result", PatObj_GetArgs(self.name + "Result"));        
            TableRefresh( self.name + "FilterBy", PatObj_GetArgs(self.name + "FilterBy"));
        }
    }
    self.OnArrangedByRender = function(p)
    {
        var div = p.row.cells[0].firstChild;
        if (p.row.getAttribute("arranged") != null && div != null)
        {
            if (p.val == "")
            {
                p.row.removeAttribute("disabled");
                p.row.style.color = "";
            }
            else
            {
            	if (div.innerHTML.indexOf(p.val) == 0)
                {
                    AddHandler(p.row, "click", p.obj.SelectRowByRow);
                    AddHandler(p.row, "mouseover", p.obj.rowMouseOver);
                    AddHandler(p.row, "mouseout", p.obj.rowMouseOut);
                    p.row.style.color = "green";
                }
                else
                {
                    RmvHandler(p.row, "click", p.obj.SelectRowByRow);
                    RmvHandler(p.row, "mouseover", p.obj.rowMouseOver);
                    RmvHandler(p.row, "mouseout", p.obj.rowMouseOut);
                    p.row.style.color = "red";
                }
            }
        }
    }
    
    var DoChk = function(obj, evt)
    {
        var name = obj.getAttribute("table");
        var rowId = obj.getAttribute("rowId");

        var params = CloneHash(self.args);
        AddHash(params, "rowId", rowId);
        AddHash(params, "value", obj.checked);

        CustServerCall("Select", self.name, params, OnSelectRes)
    }
    var OnRes = function()
    {
        TableRefresh( self.name + "Result", self.args);
        TableRefresh( self.name + "FilterBy", self.args);
        TableRefresh( self.name + "Filtered", self.args);
    }
    var OnSelectRes = function()
    {
        TableRefresh( self.name + "FilterBy", self.args);
    }
    self.PivotReport = function()
    {
        var name = self.name +  "Result";
        var params = "type=pivot&obj=" + name;
        params += "&xsl=" + self.xsl;
        params += "&args=" + escape(JSON2.stringify(self.args));
        
        window.open('PAT/Export/PVReport.aspx?' + params);
    }
    self.ExportTo = function(format)
    {
        var name = self.name +  "Result";
        var params = "export="+format+"&obj=" + name;
        params += "&args=" + escape(JSON2.stringify(self.args));
        
        window.open('PAT/Export/Export.aspx?' + params);
    }
    self.Refresh = function()
    {
        CustServerCall("Refresh", self.name, self.args, OnRes);
    }
    
    Init();    
}
