//*END_CLASS_CONTROL
//*START_CLASS_DLG_SELECT
class DlgSelect {
    /*
    static page_source="";
    static page_title="";
    static last_goods_category_id=0;
    static iddivshow=null;//div_obj se hien thi danh sach hang, khong phai la dialog
    static showlistheading=1;
    static pagesize=20;
    */

    constructor(in_page_source, in_page_title) {
        this.page_source = in_page_source;
        if (typeof in_page_title !== undefined)
            this.page_title = in_page_title;
        //this.page_title="";
        //this.last_goods_category_id=0;
        //this.iddivshow=null;
        //this.showlistheading=1;
        //this.pagesize=20;
    }
    static getRowHeadingId() {
        return "idrowheading" + this.data_struct[0].name;
    }
    //idsub neu co phai >0: goods -> units
    static getRowId(id, idsub) {
        var idrow = id;
        if (!isEmpty(idsub)) {
            if (parseInt(idsub) > 0)
                idrow += gIdCombineChar + idsub;
        }
        if (!isEmpty(this.idrowprefix))
            idrow = this.idrowprefix + gIdCombineChar + idrow;
        return "idrow" + this.data_struct[0].name + idrow;
    }
    static getRowIdMainCollapsiable(id) {
        return this.getRowId(id) + "main";
    }
    static getRowIdSubCollapsiable(id) {
        return this.getRowId(id) + "sub";
    }
    static getCellId(col_name, id) {
        return col_name + id;
    }

    //chi tiet dang bang 2 cot
    static showDetailsListForm(data) {
        if (data.length < 1) {
            showMsg("Không có dữ liệu");
            return false;
        }
        if (data.length <= g_split_row.length) {
            showMsg("Không có dữ liệu");
            return false;
        }
        var rows = [];
        var rcount = 0;
        var start = 0, arrheads;
        rows = data.split(g_split_row);
        var rcount = rows.length;
        if (rcount < 1)
            return false;
        //arrheads la array chua tieu de cac cot, neu trong rong thi cot do khong hien thi
        if (rows[start].substr(0, g_sign_columnconfig.length) == g_sign_columnconfig) {
            var datahead = rows[start].substr(g_sign_columnconfig.length);
            arrheads = datahead.split(g_split_val);
            start++;
        }
        var data_vals = [];
        data_vals = rows[start].split(g_split_val);
        var html = "";
        for (var i = 0; i < data_vals.length; i++) {
            html += "<div class='divrow'>";
            html += "<div class='divcell'>" + arrheads[i] + "</div>";
            html += "<div class='divcell'>" + data_vals[i] + "</div>";
            html += "</div>";
        }
        html = "<div class='divtable' style='width:100%'>" + html + "</div>";
        showModal(html);
    }

    //fnCallBack: fnCallBackParamArray+item.id
    //item:{id+name}
    static showItemArray(dataArray, fnCallBack, fnCallBackParamArray, fnCallBackTitle) {
        if (Array.isArray(dataArray) == false) return false;
        var strout = "", allrows = "", row = "", cmd = "";
        var i = 0, j = 0;

        for (i = 0; i < dataArray.length; i++) {
            var cmd = "";
            var paramlist = "";
            var item = dataArray[i];
            if (fnCallBack !== undefined) {
                cmd = "<input type=\"button\" class=\"buttonincell\" onclick=\"" + fnCallBack + "(";
                if (Array.isArray(fnCallBackParamArray)) {
                    for (j = 0; j < fnCallBackParamArray.length; j++) {
                        if (paramlist != "") paramlist += ",";
                        paramlist += "'" + escapeJS(fnCallBackParamArray[j].toString()) + "'";
                    }
                }
            }
            row = "<div class=\"divrow\">";
            row += "<div class=\"divcell\">" + item.id + "</div>";
            row += "<div class=\"divcell\">" + item.name + "</div>";

            if (fnCallBack !== undefined) {
                if (paramlist != "") paramlist += ",";
                paramlist += item.id;
                cmd += paramlist + ");dlgRemove();\" value=\"Chọn\">";
            }

            row += "<div class=\"divcell padding0\">" + cmd + "</div>";
            row += "</div>";
            allrows += row;
        }
        strout = "<div class='divtable'>" + allrows + "</div>";

        dlgShow(strout);
    }
    static showSimple(data, fnCallBack, fnViewOtherPage, fnViewOtherPageParams, iddivshowname, showblock) {
        var rows = [];
        var rcount = 0;
        var start = 0, pagesize = 0, pageno = 0, pagecount = 0, arrheads;

        if (data.length < 1) {
            showMsg(itxt("khongcodulieu"));
            return false;
        }
        if (data.length <= g_split_row.length) {
            showMsg(itxt("khongcodulieu"));
            return false;
        }
        rows = data.split(g_split_row);
        var rcount = rows.length;
        if (rcount < 1)
            return false;
        if (rows[0].substr(0, g_sign_pageconfig.length) == g_sign_pageconfig) {
            var configs = rows[0].split(g_split_val);
            start++;
            if (configs.length == 3) {
                pagesize = parseInt(configs[0]);
                pageno = parseInt(configs[1]);
                pagecount = parseInt(configs[2]);
            }

            if (start == rcount) {
                showMsg("Không có dữ liệu");
                return false;
            }
        }
        //arrheads la array chua tieu de cac cot, neu trong rong thi cot do khong hien thi
        if (rows[start].substr(0, g_sign_columnconfig.length) == g_sign_columnconfig) {

            var datahead = rows[start].substr(g_sign_columnconfig.length);
            arrheads = datahead.split(g_split_val);
            start++;
        }
        var strout = "", allrows = "", row = "", cmd = "";
        var i = 0, j = 0;

        for (i = start; i < rcount; i++) {
            var data_vals = [];
            data_vals = rows[i].split(g_split_val);
            var paramlist = "";
            var cmd = "";
            if (!isEmpty(fnCallBack))
                cmd = "<input type=\"button\" class=\"buttonincell\" onclick=\"" + fnCallBack + "(";
            row = "<div class=\"divrow\">";
            for (j = 0; j < data_vals.length; j++) {
                if (Array.isArray(arrheads)) {
                    if ((arrheads[j] != null) && (arrheads[j].length > 0))
                        row += "<div class=\"divcell\">" + (data_vals[j]) + "</div>";

                }
                else
                    row += "<div class=\"divcell\">" + (data_vals[j]) + "</div>";
                if (paramlist != "") paramlist += ",";
                paramlist += "'" + escapeJS(data_vals[j]) + "'";

            }
            if (!isEmpty(fnCallBack)) {
                cmd += paramlist + ");dlgRemove();\" value=\"Chọn\">";
                row += "<div class=\"divcell padding0\">" + cmd + "</div>";
            }

            row += "</div>";

            allrows += row;
        }

        var rowheading = "";
        if (DlgSelect.showlistheading == 1) {
            if (Array.isArray(arrheads)) {
                rowheading += "<div class='divrow heading' id='idrowheading'>";
                for (i = 0; i < arrheads.length; i++) {
                    if (arrheads[i] != "")
                        rowheading += "<div class='divcell'>" + arrheads[i] + "</div>";
                }
                if (!isEmpty(fnCallBack))
                    rowheading += "<div class=\"divcell\">&#9783</div>";
                rowheading += "</div>";
            }
        }
        //pageno,pagecount,fnCallBack,fnViewOtherPage,fnViewOtherPageParams
        var pageinfo = "";
        if (pagecount > 1) {
            pageinfo += "<div class='pageindex' id='idpageindex'>";
            var i = 1;
            for (i = 1; i <= pagecount; i++)
                pageinfo += "<a class=\"" + ((i == pageno) ? "pageindexfocus" : "pageindex") + "\" href=\"javascript:void(0)\" onclick=\"" + fnViewOtherPage + "(" + fnViewOtherPageParams + "," + i + ")\">" + i + "</a>";
            pageinfo += "</div>";
        }
        strout = "<div class='divtable'>" + rowheading + allrows + "</div>" + pageinfo;

        if (!isEmpty(iddivshowname)) {
            setInnerById(iddivshowname, strout);
        } else {

            if (!isEmpty(showblock)) {
                dlgShow(strout);
            } else {
                showModal(strout);
            }

        }

        return true;
    }
    static showStore(pageno, fnCallBackName, fnCallBackParams) {
        var url = "?page=list&pagesub=store&datastruct=c";
        var dataString = "";
        jQuery.ajax({
            url: url,
            data: dataString,
            type: "GET",
            success: function (data) {
                data = getDataOk(data);
                var strout = DlgSelect.formatDataAsGrid(data, ds_store_c, fnCallBackName, fnCallBackParams);
                strout += "<input type=\"button\" class=\"btndlg cancel\" style=\"width:100%\" value=\"Đóng\" onclick=\"dlgRemove();\">";
                dlgShow(strout, itxt("chonkho"));
                UiControl.inputWithClearButtonSetup();
                //setFocus("scontactname");
            },
            error: function () {
                hideModal();
            }
        });
    }
    static showGoodsCategory(pageno, fnCallBackName, fnCallBackParamArray) {
        if (isEmpty(fnCallBackName)) fnCallBackName = "";
        if (isEmpty(fnCallBackParamArray)) fnCallBackParamArray = "";
        if (isEmpty(pageno)) pageno = 1;

        if (g_list_goodscategory.length < 1) {
            getListGoodsCategory("DlgSelect.showGoodsCategory", [pageno, fnCallBackName, fnCallBackParamArray]);
            return;
        }
        var allrows = "";
        var i = 0, j = 0;
        var rcount = g_list_goodscategory.length;

        for (i = 0; i < rcount; i++) {
            var data_vals = g_list_goodscategory[i];

            var cmd = "", button = "";
            cmd = fnCallBackName + "(";
            if (!isEmpty(fnCallBackParamArray))
                cmd += arrayToStringAsList(fnCallBackParamArray) + ",";
            cmd += "'" + data_vals[0] + "'";
            for (var j = 1; j < data_vals.length; j++) {
                if (isString(data_vals[j]))
                    cmd += ",'" + escapeJS(data_vals[j]) + "'";
                else
                    cmd += "," + data_vals[j];
            }
            cmd += ");";

            allrows += "<div class=\"divrow\" onclick=\"hideModal();" + cmd + "\">";
            var firstCellVisibleTitle = "";
            for (var j = 1; j < data_vals.length; j++) {
                if (dsIsVisible(ds_goods_category, j)) {
                    var value = "", style = "";
                    value = data_vals[j];
                    if (ds_goods_category[j].type == "number") {
                        style = "text-align:right;";
                        value = formatNumberZS(value);
                    }
                    var cellclass = "divcell";
                    if (firstCellVisibleTitle.length == 0) {
                        cellclass += " click";
                        firstCellVisibleTitle = value;
                    }
                    if (ds_goods_category[j].width != "") style += "width:" + dsGetWidth(ds_goods_category, j) + ";";
                    allrows += "<div class='" + cellclass + "' style='" + style + "' id='" + DlgSelect.getCellId(ds_goods_category[j].name, data_vals[0]) + "'>" + value + "</div>";
                }
                else {
                    value = data_vals[j];
                    allrows += "<input type='hidden' id='" + DlgSelect.getCellId(ds_goods_category[j].name, data_vals[0]) + "' value='" + value + "'>";
                }
            }

            button = "<input type=\"button\" class=\"buttonincell addimage\" placeholder=\"" + itxt("cmd_chon") + "\" onclick=\"event.stopPropagation();setModalHeading('" + escapeJS(firstCellVisibleTitle) + "');" + cmd + "\">";
            allrows += "<div class=\"divcell padding0\" style=\"width:" + g_ui_cmdwidth + "px\">" + button + "</div>";
            allrows += "</div>";
        }
        allrows = "<div class='divtable'>" + allrows + "</div>";
        showModal(allrows, itxt("chonnhomhang"));
    }
    //call back on goods select
    //fnCallBackName co the dang "abc('a')"
    static showGoods(pageno, fnCallBackName, fnCallBackParam, dlgtitle, show_stock, store_id, category_id, goods_name, invoice_type) {
        if (isEmpty(pageno)) pageno = 1;
        if (isEmpty(fnCallBackName)) fnCallBackName = "";
        if (isEmpty(fnCallBackParam)) fnCallBackParam = "[]";

        if (isEmpty(show_stock)) show_stock = 0;
        if (isEmpty(store_id)) store_id = 0;
        if (isEmpty(category_id)) category_id = 0;
        if (isEmpty(goods_name)) goods_name = "";
        if (isEmpty(invoice_type)) invoice_type = "";

        if (DlgSelect.last_goods_category_id != 0)
            category_id = DlgSelect.last_goods_category_id;

        if (g_list_goodscategory.length < 1) {

            getListGoodsCategory("DlgSelect.showGoods", [pageno, fnCallBackName, fnCallBackParam, dlgtitle, show_stock, store_id, category_id, goods_name, invoice_type]);
            return;
        }

        if (!isEmpty(goods_name))
            goods_name = uriEncode(goods_name);
        else
            goods_name = "";
        var url = "?page=list&pagesub=goods&store_id=" + store_id + "&category_id=" + category_id + "&show_stock=" + show_stock + "&invoice_type=" + invoice_type + "&goods_name=" + (goods_name) + "&pageno=" + pageno + "&pagesize=" + DlgSelect.pagesize;

        var dataString = "";
        jQuery.ajax({
            url: url,
            data: dataString,
            type: "GET",
            success: function (data) {
                data = getDataOk(data);
                var option_select = "<option value='0'></option>";
                for (i = 0; i < g_list_goodscategory.length; i++) {
                    if (g_list_goodscategory[i][0] == category_id)
                        option_select += "<option value=" + g_list_goodscategory[i][0] + " selected>" + g_list_goodscategory[i][1] + "</option>";
                    else
                        option_select += "<option value=" + g_list_goodscategory[i][0] + ">" + g_list_goodscategory[i][1] + "</option>";
                }

                var strout = "", strgrid = "";
                //xem phan khung: combo nhom hang, hop tim ten hang da co hay chua.
                //showGoods(pageno,fnOnSelectCallBack,dlgtitle,show_stock,store_id,category_id,goods_name,invoice_type)
                var iddlgselectvariableareashowgoods = document.getElementById("iddlgselectvariableareashowgoods");
                if ((iddlgselectvariableareashowgoods === null) || (!isModalVisible())) {
                    var strsgoodsname = '<input type="search" placeholder="(tên hàng)" name="sgoodsname" id="sgoodsname" oninput="var sgoodsname=document.getElementById(\'sgoodsname\').value;' +
                        'DlgSelect.showGoods(1,\'' + escapeHtmlJs(fnCallBackName) + '\',[' + arrayToStringAsList(fnCallBackParam) + '],\'' + dlgtitle + '\',' + show_stock + ',' + store_id + ',0,sgoodsname,' + '\'' + invoice_type + '\');"' +
                        ' value="' + goods_name + '" onchange="this.selectionStart = this.selectionEnd =0;" style="width:100%">';
                    strout += '<div style="width:100%">';
                    strout += '<div style="width:55%;float:left">' + strsgoodsname + '</div>';
                    strout += '<div style="width:45%;float:right"><select style="width:100%" onchange="' +
                        'DlgSelect.showGoods(1, \'' + escapeHtmlJs(fnCallBackName) + '\',[' + arrayToStringAsList(fnCallBackParam) + '],\'' + dlgtitle + '\',' + show_stock + ',' + store_id + ',this.value,\'\',' + '\'' + invoice_type + '\');"' + '>' + option_select + '</select></div>';
                    strout += '</div>';
                }
                DlgSelect.data_struct = cloneArrayObj(ds_goods_stock);

                for (var idx = 0; idx < DlgSelect.data_struct.length; idx++) {
                    DlgSelect.data_struct[idx].visible = "";
                    DlgSelect.data_struct[idx].width = "";
                    DlgSelect.data_struct[idx].subinfo = "";
                    DlgSelect.data_struct[idx].merge = "";
                }
                DlgSelect.data_struct[3].width = "55%";//ten hang
                DlgSelect.data_struct[3].visible = 1;
                DlgSelect.data_struct[6].width = "15%";//ton
                DlgSelect.data_struct[6].visible = 1;
                DlgSelect.data_struct[7].width = "calc(30% - " + g_ui_cmdwidth + "px)";//don gia
                DlgSelect.data_struct[7].visible = 1;

                strgrid = DlgSelect.showGoods_Grid(data, "DlgSelect.showGoods", fnCallBackName, fnCallBackParam, dlgtitle, show_stock, store_id, category_id, goods_name, invoice_type);
                if (DlgSelect.iddivshow != null) {
                    if (iddlgselectvariableareashowgoods === null) {
                        strgrid = '<div id="iddlgselectvariableareashowgoods">' + strgrid + '</div>';
                        strout += strgrid;
                        DlgSelect.iddivshow.innerHTML = strout;
                        UiControl.inputWithClearButtonSetup();
                    } else {
                        iddlgselectvariableareashowgoods.innerHTML = strgrid;
                    }
                    setFocus("sgoodsname");
                }

                else {


                    if ((iddlgselectvariableareashowgoods === null) || (!isModalVisible())) {

                        if (isEmpty(dlgtitle)) dlgtitle = itxt("chonhang");
                        strgrid = '<div id="iddlgselectvariableareashowgoods">' + strgrid + '</div>';
                        strout += strgrid;
                        showModal(strout, dlgtitle);
                        UiControl.inputWithClearButtonSetup();
                        setFocus("sgoodsname");
                    }
                    else {
                        setInnerById("iddlgselectvariableareashowgoods", strgrid);
                    }

                }
            },
            error: function () {
                hideModalBlock();
            }
        });
    }
    static getIdSub(data_vals) {
        if (isEmpty(this.data_struct[0].idsub)) return 0;
        var nsub = parseInt(this.data_struct[0].idsub);
        if ((nsub > 0) && (nsub < this.data_struct.length)) {
            return parseInt(data_vals[nsub]);
        }
        return 0;
    }

    static getPageIndexGoTo(page, pagemax, fnViewOtherPage, fnViewOtherPageParams) {
        var fstring = fnViewOtherPage + "(getValById('idpageindexinput')," + arrayToStringAsList(fnViewOtherPageParams) + ")";

        var idpageindex = document.getElementById("idpageindex");
        var htmlold = idpageindex.innerHTML;
        var htmlnew = "<input type=\"text\" onfocus=\"this.select()\" size=\"5\" style=\"height:100%;padding:5px\" id=\"idpageindexinput\" value=\"" + page + "\">";
        htmlnew += "<input type=\"button\" style=\"width:60px;height:100%;padding:5px\" value=\"Xem\" onclick=\"" + escapeHTML(fstring) + "\">";
        idpageindex.innerHTML = htmlnew;
    }
    static getPageIndexSelectOnClickString(pageno, fnViewOtherPage, fnViewOtherPageParams) {
        var fstring = fnViewOtherPage + "(" + pageno;
        fstring += "," + fnViewOtherPageParams + ")";
        return fstring;
    }
    static getPageIndexSelect(pageno, pagecount, fnViewOtherPage, fnViewOtherPageParams) {
        if (pagecount <= 1)
            return "";
        var pageinfo = "";
        pageinfo += "<div class='pageindex' id='idpageindex'>";
        var i = 1;
        var strViewOtherPageParams = fnViewOtherPageParams;
        if (pagecount <= 9) {
            for (i = 1; i <= pagecount; i++)
                pageinfo += "<a class=\"" + ((i == pageno) ? "pageindexfocus" : "pageindex") + "\" href=\"javascript:void(0)\" onclick=\"" + DlgSelect.getPageIndexSelectOnClickString(i, fnViewOtherPage, fnViewOtherPageParams) + "\">" + i + "</a>";
        }
        else {
            pageinfo += "<a class=\"pageindex\" href=\"javascript:void(0)\" onclick=\"" + DlgSelect.getPageIndexSelectOnClickString(pageno - 1, fnViewOtherPage, fnViewOtherPageParams) + "\">&#8592</a>";
            pageinfo += "<a class=\"" + ((1 == pageno) ? "pageindexfocus" : "pageindex") + "\" href=\"javascript:void(0)\" onclick=\"" + DlgSelect.getPageIndexSelectOnClickString(1, fnViewOtherPage, fnViewOtherPageParams) + "\">1</a>";

            var hstart = 0, hend = 0, tstart = 0, tend = 0;
            if (pageno <= 3) {
                hstart = 2; hend = 5; tstart = 0; tend = -1;
                for (i = hstart; i <= hend; i++)
                    pageinfo += "<a class=\"" + ((i == pageno) ? "pageindexfocus" : "pageindex") + "\" href=\"javascript:void(0)\" onclick=\"" + DlgSelect.getPageIndexSelectOnClickString(i, fnViewOtherPage, fnViewOtherPageParams) + "\">" + i + "</a>";
                pageinfo += "<a class=\"pageindex\" href=\"javascript:void(0)\" onclick=\"DlgSelect.getPageIndexGoTo(" + (hend + 1) + "," + pagecount + ",'" + fnViewOtherPage + "',[" + strViewOtherPageParams + "])\">...</a>";

            }
            else if (pageno > (pagecount - 3)) {
                hstart = 0; hend = -1; tstart = pagecount - 4; tend = pagecount - 1;
                pageinfo += "<a class=\"pageindex\" href=\"javascript:void(0)\" onclick=\"DlgSelect.getPageIndexGoTo(" + (tstart - 1) + "," + pagecount + ",'" + fnViewOtherPage + "',[" + strViewOtherPageParams + "])\">...</a>";
                for (i = tstart; i <= tend; i++)
                    pageinfo += "<a class=\"" + ((i == pageno) ? "pageindexfocus" : "pageindex") + "\" href=\"javascript:void(0)\" onclick=\"" + DlgSelect.getPageIndexSelectOnClickString(i, fnViewOtherPage, fnViewOtherPageParams) + "\">" + i + "</a>";
            }
            else {
                hstart = pageno - 1; hend = pageno + 1; tstart = 0; tend = -1;
                pageinfo += "<a class=\"pageindex\" href=\"javascript:void(0)\" onclick=\"DlgSelect.getPageIndexGoTo(" + (pageno - 2) + "," + pagecount + ",'" + fnViewOtherPage + "',[" + strViewOtherPageParams + "])\">...</a>";
                for (i = hstart; i <= hend; i++)
                    pageinfo += "<a class=\"" + ((i == pageno) ? "pageindexfocus" : "pageindex") + "\" href=\"javascript:void(0)\" onclick=\"" + DlgSelect.getPageIndexSelectOnClickString(i, fnViewOtherPage, fnViewOtherPageParams) + "\">" + i + "</a>";
                pageinfo += "<a class=\"pageindex\" href=\"javascript:void(0)\" onclick=\"DlgSelect.getPageIndexGoTo(" + (pageno + 2) + "," + pagecount + ",'" + fnViewOtherPage + "',[" + strViewOtherPageParams + "])\">...</a>";

            }
            pageinfo += "<a class=\"" + ((pageno == pagecount) ? "pageindexfocus" : "pageindex") + "\" href=\"javascript:void(0)\" onclick=\"" + DlgSelect.getPageIndexSelectOnClickString(pagecount, fnViewOtherPage, fnViewOtherPageParams) + "\">" + pagecount + "</a>";
            pageinfo += "<a class=\"pageindex\" href=\"javascript:void(0)\" onclick=\"" + DlgSelect.getPageIndexSelectOnClickString(pageno + 1, fnViewOtherPage, fnViewOtherPageParams) + "\">&#8594</a>";
        }
        pageinfo += "</div>";
        return pageinfo;
    }
    //data_vals: array of value current row, j:position of value (cell)
    static getSubInfoValue(data_vals, j) {
        var subinfo = "";
        if (Array.isArray(this.data_struct[j].subinfo)) {
            for (var n = 0; n < this.data_struct[j].subinfo.length; n++) {
                var subindex = this.data_struct[j].subinfo[n];
                if (isEmpty(this.data_struct[subindex].subinfobreak))
                    subinfo += "<br>";
                else
                    subinfo += this.data_struct[subindex].subinfobreak;
                subinfo += data_vals[subindex];
            }
        }
        else {
            subinfo += data_vals[this.data_struct[j].subinfo];
        }
        return subinfo;
    }
    //fnCallBack duoc goi voi danh sach param: paramsCallBack, param record data
    static formatAsDataGrid2(data, fnCallBack, paramsCallBack, fnCallBackTitle) {
        var rows;
        if (Array.isArray(data)) {
            rows = data;
        }
        else {
            if (data.length <= g_split_row.length)
                return "";
            rows = data.split(g_split_row);
        }

        var rcount = rows.length;
        if (rcount < 1)
            return "";
        var start = 0, pagesize = 0, pageno = 0, pagecount = 0, arrheads;
        //rows[0] co the la du lieu, khong phai la config
        if (isString(rows[0])) {
            if (rows[0].substr(0, g_sign_pageconfig.length) == g_sign_pageconfig) {
                var configs = rows[0].split(g_split_val);
                start++;
                if (configs.length == 3) {
                    pagesize = parseInt(configs[0]);
                    pageno = parseInt(configs[1]);
                    pagecount = parseInt(configs[2]);
                }
            }
        }

        if (isString(rows[start])) {
            //arrheads la array chua tieu de cac cot, neu trong rong thi cot do khong hien thi
            if (rows[start].substr(0, g_sign_columnconfig.length) == g_sign_columnconfig) {
                var datahead = rows[start].substr(g_sign_columnconfig.length);
                arrheads = datahead.split(g_split_val);
                start++;
            }
        }

        var strout = "", allrows = "";
        var i = 0, j = 0;

        for (i = start; i < rcount; i++) {
            var data_vals = rows[i].split(g_split_val);
            var cmd = "", paramlist = "";
            cmd = "<input type=\"button\" class=\"buttonincell\" value=\"" + escapeHTML(fnCallBackTitle) + "\" onclick=\"dlgRemove();" + escapeHTML(fnCallBack) + "(";
            if (Array.isArray(paramsCallBack))
                paramlist = arrayToStringAsList(paramsCallBack);
            var row = "<div class=\"divrow\">";
            for (j = 0; j < data_vals.length; j++) {
                if (Array.isArray(arrheads)) {
                    if (arrheads[j] != "")
                        row += "<div class=\"divcell\">" + escapeHTML(data_vals[j]) + "</div>";
                }
                else
                    row += "<div class=\"divcell\">" + escapeHTML(data_vals[j]) + "</div>";

                if (paramlist.length > 0)
                    paramlist += ",";
                paramlist += "'" + escapeJS(data_vals[j].toString()) + "'";
            }
            cmd += paramlist;
            cmd += ");\">";
            row += "<div class=\"divcell padding0\" style=\"width:" + g_ui_cmdwidth + "px\">" + (cmd) + "</div>";
            row += "</div>";
            allrows += row;
        }

        var rowheading = "";
        if (DlgSelect.showlistheading == 1) {
            if (Array.isArray(arrheads)) {
                rowheading += "<div class='divrow heading' id='idrowheading'>";
                for (i = 0; i < arrheads.length; i++) {
                    if (arrheads[i] != "")
                        rowheading += "<div class='divcell'>" + arrheads[i] + "</div>";
                }
                rowheading += "<div class='divcell' style='width:" + g_ui_cmdwidth + "px'>&#9783</div>";
                rowheading += "</div>";
            }
        }
        strout = "<div class='divtable'>" + rowheading + allrows + "</div>";
        return strout;
    }
    //row luon co cau truc id,data1,data2..
    //DlgSelect.showGoods_Grid(data, "DlgSelect.showGoods", fnCallBackName, fnCallBackParam, dlgtitle, show_stock, store_id, category_id, goods_name, invoice_type);
    static showGoods_Grid(data, fnViewOtherPage, fnCallBackName, fnCallBackParams, dlgtitle, show_stock, store_id, category_id, goods_name, invoice_type) {
        var rows;
        if (Array.isArray(data)) {
            rows = data;
        }
        else {
            if (data.length <= g_split_row.length)
                return "";
            rows = data.split(g_split_row);
        }
        var rcount = rows.length;
        if (rcount < 1)
            return "";
        var start = 0, pagesize = 0, pageno = 0, pagecount = 0, arrheads;
        if (rows[0].substr(0, g_sign_pageconfig.length) == g_sign_pageconfig) {
            var configs = rows[0].split(g_split_val);
            start++;
            if (configs.length == 3) {
                pagesize = parseInt(configs[0]);
                pageno = parseInt(configs[1]);
                pagecount = parseInt(configs[2]);
            }
        }
        //arrheads la array chua tieu de cac cot, neu trong rong thi cot do khong hien thi
        //dinh dang data_struct nen bo qua
        if (rows[start].substr(0, g_sign_columnconfig.length) == g_sign_columnconfig) {
            start++;
        }
        var strout = "", allrows = "";
        var i = 0, j = 0;

        for (i = start; i < rcount; i++) {
            var data_vals = rows[i].split(g_split_val);
            var cmd = "", button = "";
            cmd = fnCallBackName + "(";
            if (Array.isArray(fnCallBackParams) && (fnCallBackParams.length > 0)) {
                cmd += arrayToStringAsList(fnCallBackParams) + ",";
            }
            cmd += "'" + data_vals[0] + "'";
            for (var j = 1; j < data_vals.length; j++) {
                if (isString(data_vals[j]))
                    cmd += ",'" + escapeJS(data_vals[j]) + "'";
                else
                    cmd += "," + data_vals[j];
            }
            cmd += ");";

            var id = data_vals[0];
            var idsub = this.getIdSub(data_vals);
            var idrow = this.getRowId(data_vals[0], idsub, "dlgs");
            var firstCellVisibleTitle = "";
            allrows += "<div class=\"divrow\" onclick=\"hideModal();" + escapeJS(cmd) + "\">";
            for (var j = 1; j < data_vals.length; j++) {
                if (dsIsVisible(this.data_struct, j)) {
                    var value = "", style = "";
                    if (this.data_struct[j].merge == 1) {
                        value = data_vals[j];
                    }
                    else if (this.data_struct[j].type == "check") {
                        if ((data_vals[j] == "") || (data_vals[j] == "0"))
                            value = "";
                        else {
                            value = g_char_yes;
                            style = "text-align:center;";
                        }
                    }
                    else {
                        value = data_vals[j];
                        if (this.data_struct[j].type == "number") {
                            style = "text-align:right;";
                            value = formatNumberZS(value);
                        }
                    }
                    //thong tin phu
                    if (!isEmpty(this.data_struct[j].subinfo)) {
                        var subinfo = this.getSubInfoValue(data_vals, j);
                        value = "<b1>" + value + "</b1>" + subinfo;
                    }
                    var cellclass = "divcell";
                    if (firstCellVisibleTitle.length == 0) {
                        cellclass += " click";
                        firstCellVisibleTitle = data_vals[j];//setModalHeading nen du lieu raw, khong ma html
                    }
                    if (dsGetWidth(this.data_struct, j) != "") style += "width:" + dsGetWidth(this.data_struct, j) + ";";
                    allrows += "<div class='" + cellclass + "' style='" + style + "' id='" + this.getCellId(this.data_struct[j].name, data_vals[0]) + "'>" + value + "</div>";
                }
                else {
                    value = data_vals[j];
                    allrows += "<input type='hidden' id='" + this.getCellId(this.data_struct[j].name, data_vals[0]) + "' value='" + value + "'>";
                }
            }
            button = "<input type=\"button\" class=\"buttonincell addimage\" placeholder=\"" + escapeJS(itxt("cmd_chon")) + "\" onclick=\"event.stopPropagation();setModalHeading('" + escapeHTML(escapeJS(firstCellVisibleTitle)) + "');" + escapeHTML(cmd) + "\">";
            allrows += "<div class=\"divcell padding0\" style=\"width:" + g_ui_cmdwidth + "px\">" + button + "</div>";
            allrows += "</div>";
        }

        var rowheading = "";
        if (DlgSelect.showlistheading == 1) {
            rowheading += "<div class='divrow heading' id='idrowheading'>";
            for (i = 0; i < this.data_struct.length; i++) {
                if (dsIsVisible(this.data_struct, i)) {
                    var style = "";
                    if (dsGetWidth(this.data_struct, i) != "") style += "width:" + dsGetWidth(this.data_struct, i) + ";";
                    rowheading += "<div class='divcell' style='" + style + "'>" + this.data_struct[i].head + "</div>";

                }
            }
            rowheading += "<div class='divcell cmd' style='width:" + g_ui_cmdwidth + "px'>&#9783</div>";
            rowheading += "</div>";

        }
        var pageinfo = "";
        //loai tru [234.5.5] => '234.5.5'
        if (Array.isArray(fnCallBackParams)) {
            fnCallBackParams = arrayToStringAsList(fnCallBackParams);
        }

        pageinfo = DlgSelect.getPageIndexSelect(pageno, pagecount, fnViewOtherPage,
            new Array("'" + escapeHtmlJs(fnCallBackName) + "',[" + fnCallBackParams + "],'" + escapeHTML(dlgtitle) + "'," + show_stock + "," + store_id + "," + category_id + ",'" + escapeHTML(goods_name) + "','" + invoice_type + "'"));
        strout = "<div class='divtable'>" + rowheading + allrows + "</div>" + pageinfo;
        return strout;
    }

    //row/datastruct luon co cau truc id,data1,data2..
    static formatDataAsGrid(data, datastruct, fnCallBackName, fnCallBackParams, fnViewOtherPage, fnViewOtherPageParams) {

        var rows;
        if (Array.isArray(data)) {
            rows = data;
        }
        else {
            if (data.length <= g_split_row.length)
                return "";
            rows = data.split(g_split_row);
        }
        var rcount = rows.length;
        if (rcount < 1)
            return "";

        var start = 0, pagesize = 0, pageno = 0, pagecount = 0, arrheads;
        if (rows[0].substr(0, g_sign_pageconfig.length) == g_sign_pageconfig) {
            var configs = rows[0].split(g_split_val);
            start++;
            if (configs.length == 3) {
                pagesize = parseInt(configs[0]);
                pageno = parseInt(configs[1]);
                pagecount = parseInt(configs[2]);
            }
        }

        //arrheads la array chua tieu de cac cot, neu trong rong thi cot do khong hien thi
        if (rows[start].substr(0, g_sign_columnconfig.length) == g_sign_columnconfig) {
            var datahead = rows[start].substr(g_sign_columnconfig.length);
            arrheads = datahead.split(g_split_val);
            start++;
        }
        var strout = "", allrows = "";
        var i = 0, j = 0;

        for (i = start; i < rcount; i++) {
            var data_vals = rows[i].split(g_split_val);
            if (data_vals.length < datastruct.length) {
                continue;
            }
            var cmd = "";
            cmd = fnCallBackName + "(";
            if (Array.isArray(fnCallBackParams) && (fnCallBackParams.length > 0)) {

                for (var k = 0; k < fnCallBackParams.length; k++) {
                    if (k > 0) cmd += ',';
                    if (isString(fnCallBackParams[k]))
                        cmd += "'" + escapeJS(fnCallBackParams[k]) + "'";
                    else
                        cmd += fnCallBackParams[k];
                }
                cmd += ",";
            }

            cmd += data_vals[0];
            for (var j = 1; j < data_vals.length; j++) {
                cmd += ",'" + escapeJS(data_vals[j]) + "'";
            }
            cmd += ");";

            allrows += "<div class=\"divrow\" onclick=\"dlgRemove();" + escapeHTML(cmd) + "\">";

            for (var j = 1; j < data_vals.length; j++) {
                if (dsGetVisible(datastruct, j) == 0) continue;
                var subinfo = "", cell = "";

                var cw = dsGetWidth(datastruct, j);
                if (j == (data_vals.length - 1)) {
                    cw = dsGetWidth(datastruct, j) + " - " + g_ui_cmdwidth + "px";
                }
                allrows += "<div class=\"divcell\" style=\"width:" + cw + "\">";
                if (Array.isArray(arrheads)) {
                    if (arrheads[j] != "") {
                        cell = escapeHTML(data_vals[j])
                    }
                }
                else {
                    cell = escapeHTML(data_vals[j]);
                }
                //thong tin phu
                if (!isEmpty(datastruct[j].subinfo)) {
                    var sclass = "", svalue = "";
                    for (var n = 0; n < datastruct[j].subinfo.length; n++) {
                        sclass = "";
                        var subindex = datastruct[j].subinfo[n];
                        if (isEmpty(datastruct[subindex].subinfobreak))
                            subinfo += "<br>";
                        else
                            subinfo += datastruct[subindex].subinfobreak;
                        svalue = data_vals[subindex];
                        if (datastruct[subindex].type == "number") svalue = formatNumberZS(svalue);
                        if (!isEmpty(datastruct[subindex].subinfoclass)) sclass = datastruct[subindex].subinfoclass;
                        if (!isEmpty(datastruct[subindex].class)) sclass = datastruct[subindex].class;
                        var scellid = this.getCellId(datastruct[subindex].name, data_vals[0]);
                        subinfo += "<span id='" + scellid + "' class='" + sclass + "'>" + svalue + "</span>";
                    }


                }
                if (!isEmpty(datastruct[j].maininfoclass))
                    cell = "<span class='" + datastruct[j].maininfoclass + "'>" + cell + "</span>";
                if (!isEmpty(datastruct[j].subinfoclass))
                    cell += "<span class='" + datastruct[j].subinfoclass + "'>" + subinfo + "</span>";
                else
                    cell += subinfo;
                allrows += cell;
                allrows += "</div>";
            }
            var button = "<input type=\"button\" class=\"buttonincell addimage\" onclick=\"event.stopPropagation();setModalHeading('OK');" + escapeHTML(cmd) + "\">";
            allrows += "<div class=\"divcell padding0\" style=\"width:" + g_ui_cmdwidth + "px\">" + button + "</div>";
            allrows += "</div>";
        }

        var rowheading = "";
        if (DlgSelect.showlistheading == 1) {
            if (Array.isArray(arrheads)) {
                rowheading += "<div class='divrow heading' id='idrowheading'>";
                for (i = 0; i < arrheads.length; i++) {
                    if (arrheads[i] != "")
                        rowheading += "<div class='divcell' style='width:" + dsGetWidth(datastruct, i) + "'>" + arrheads[i] + "</div>";
                }
                rowheading += "<div class='divcell' style='width:" + g_ui_cmdwidth + "px'>&#9783</div>";
                rowheading += "</div>";
            }
        }
        var pageinfo = "";

        pageinfo = DlgSelect.getPageIndexSelect(pageno, pagecount, fnViewOtherPage, fnViewOtherPageParams);
        strout = "<div class='divtable'>" + rowheading + allrows + "</div>" + pageinfo;
        return strout;
    }
    //hien thi select hoac trac ve chuoi option cua select
    static showDataToSelectBox(idselectbox, data, zeroitemfist, valselected) {
        var rows = data.split(g_split_row);
        if (!Array.isArray(rows)) return false;
        var stroptions = ""
        var start = 0;
        if (rows[0].substr(0, g_sign_pageconfig.length) == g_sign_pageconfig)
            start++;
        //arrheads la array chua tieu de cac cot, neu trong rong thi cot do khong hien thi
        if (rows[start].substr(0, g_sign_columnconfig.length) == g_sign_columnconfig)
            start++;
        for (i = start; i < rows.length; i++) {
            var vals = rows[i].split(g_split_val);
            if (vals.length >= 2) {
                var label = vals[1];
                for (var j = 2; j < vals.length; j++)label += " - " + vals[j];
                stroptions += "<option value=\"" + vals[0] + "\"" + strSelected(vals[0], valselected) + " >" + label + "</option>";
            }
        }
        if (zeroitemfist !== undefined) stroptions = "<option value='0'>" + zeroitemfist + "</option>" + stroptions;
        if (isEmpty(idselectbox)) {
            return stroptions;
        }
        else {
            idselectbox = document.getElementById(idselectbox);
            idselectbox.innerHTML = stroptions;
            return true;
        }
    }
    static showTimeSelect(fnCallBack) {
        var today = new Date();
        //var dd = String(today.getDate()).padStart(2, '0');
        //var mm = String(today.getMonth() + 1).padStart(2, '0'); //January is 0!
        //var yyyy = String(today.getFullYear());

        var strout = "";
        strout += '<div class="divtable" style="background:#039;color:#0C3;font-weight:bold">';
        strout += '<div class="divrow">';
        strout += '<div class="divcell" style="padding:0px"><input type="text" id="iddthour" onfocus="this.select()" style="width:100%" value="" placeholder="giờ"></div>';
        strout += '<div class="divcell" style="padding:0px"><input type="text" id="iddtmin" onfocus="this.select()" style="width:100%" value="" placeholder="phút"></div>';
        strout += '<div class="divcell" style="padding:0px"><input type="text" id="iddtday" value="' + today.getDate() + '" onfocus="this.select()" style="width:100%" value="" placeholder="ngày"></div>';
        strout += '<div class="divcell" style="padding:0px"><input type="text" id="iddtmonth" value="' + (today.getMonth() + 1) + '"onfocus="this.select()" style="width:100%" value="" placeholder="tháng"></div>';
        strout += '<div class="divcell" style="padding:0px"><input type="text" id="iddtyear" value="' + today.getFullYear() + '"onfocus="this.select()" style="width:100%" value="" placeholder="năm"></div>';
        strout += '</div>';
        strout += '</div>';
        strout += '<div style=\"width:100%\">';
        strout += "<input type=\"button\" class=\"btndlg cancel\" style=\"width:50%\" value=\"Bỏ qua\" onclick=\"dlgRemove();\">";
        strout += "<input type=\"submit\" class=\"btndlg ok\" style=\"width:50%\" value=\"Đồng ý\" onclick=\"" + fnCallBack + "(getValById('iddthour'),getValById('iddtmin'),getValById('iddtday'),getValById('iddtmonth'),getValById('iddtyear'));dlgRemove();\"";
        strout += '</div>';
        dlgShow(strout);
    }
    //hien thi danh sach gom ca tieu de cot
    //fnCallBackName: String -> 'onGoodsSelect'
    static showContact(pageno, fnCallBackName, fnCallBackParams, contactname, contactphone, contactaddress, contacttype, iddlg) {
        var iddlgshow = iddlg;
        if (isEmpty(iddlgshow)) iddlgshow = dlgGetNewId();
        if (isEmpty(contactname)) contactname = "";
        if (isEmpty(contactaddress)) contactaddress = "";
        if (isEmpty(contactphone)) contactphone = "";
        if (isEmpty(contacttype)) contacttype = 3;
        if (isEmpty(fnCallBackParams)) fnCallBackParams = [];
        var ds = ds_contact_c;
        if (g_viewmode == 0) ds = ds_contact_combo;

        var url = "?page=list&pagesub=contact&datastruct=c&type=" + contacttype + "&contactname=" + uriEncode(contactname) +
            "&contactaddress=" + uriEncode(contactaddress) + "&contactphone=" + uriEncode(contactphone) +
            "&invoice_type=phieuxuatle&pageno=" + pageno;
        var dataString = "";
        jQuery.ajax({
            url: url,
            data: dataString,
            type: "GET",
            success: function (data) {
                data = getDataOk(data);
                var strout = "", stroninput;
                //phan fix duoc tao 01 lan khi hien thi lan dau
                //cac lan sau se hien thi phan noi dung
                var iddlgselectvariableareashowcontact = document.getElementById("iddlgselectvariableareashowcontact");
                //||(!isModalVisible() -> only in showModal
                if (iddlgselectvariableareashowcontact === null) {

                    stroninput = "var scontactname=document.getElementById(\'scontactname\').value;" +
                        " var scontactaddress=document.getElementById(\'scontactaddress\').value;" +
                        " var scontactphone=document.getElementById(\'scontactphone\').value;" +
                        " DlgSelect.showContact(0,\'" + fnCallBackName + "\',[";
                    stroninput += arrayToStringAsList(fnCallBackParams);
                    stroninput += "],scontactname,scontactphone,scontactaddress," + contacttype + ",'" + iddlgshow + "')";

                    var scontactname = '<input placeholder="(tên)" type="search" name="scontactname" id="scontactname"' +
                        ' style="width:45%;float:left;"' +
                        ' oninput="' + stroninput + '"' +
                        ' onchange="this.selectionStart = this.selectionEnd =0;">';

                    var scontactphone = '<input placeholder="(điện thoại)" name="scontactphone" id="scontactphone"' +
                        ' type="search" style="width:25%;float:left"' +
                        ' oninput="' + stroninput + '"' +
                        ' onchange="this.selectionStart = this.selectionEnd =0;">';

                    var scontactaddress = '<input placeholder="(địa chỉ)" name="scontactaddress" id="scontactaddress"' +
                        ' type="search" style="width:30%;float:right;"' +
                        ' oninput="' + stroninput + '"' +
                        ' onchange="this.selectionStart = this.selectionEnd =0;">';

                    strout += '<div style="width:100%">' + scontactname + scontactphone + scontactaddress + '</div>';

                    strout += '<div id="iddlgselectvariableareashowcontact">';
                    strout += DlgSelect.formatDataAsGrid(data, ds, fnCallBackName, fnCallBackParams,
                        "DlgSelect.showContact", new Array("'" + fnCallBackName + "',[" + arrayToStringAsList(fnCallBackParams)
                            + "],'" + contactname + "'", "'" + contactphone + "'", "'" + contactaddress
                            + "'," + contacttype + ",'" + iddlgshow + "'"));
                    strout += '</div>';
                    strout += "<input type=\"button\" class=\"btndlg default\" style=\"width:50%\" value=\"Bỏ chọn\" onclick=\"dlgRemove();" + fnCallBackName + "(" + arrayToStringAsList(fnCallBackParams) + ");\">";
                    strout += "<input type=\"button\" class=\"btndlg cancel\" style=\"width:50%\" value=\"Đóng\" onclick=\"dlgRemove();\">";

                    dlgShow(strout, itxt("chondoitac"), iddlg);
                    UiControl.inputWithClearButtonSetup();
                    setFocus("scontactname");
                }
                else {
                    setInnerById("iddlgselectvariableareashowcontact",
                        DlgSelect.formatDataAsGrid(data, ds, fnCallBackName, fnCallBackParams,
                            "DlgSelect.showContact", new Array("'" + fnCallBackName
                                + "',[" + arrayToStringAsList(fnCallBackParams) + "],'" + escapeHTML(contactname)
                                + "'", "'" + escapeHTML(contactphone) + "'", "'" + escapeHTML(contactaddress) + "'," + contacttype + ",'" + iddlgshow + "'")));
                }
            },
            error: function () {
                hideModal();
            }
        });

    }

    static showUser(pageno, fnCallBackName, fnCallBackParams, iddlg) {
        var iddlgshow = iddlg;
        if (isEmpty(iddlgshow)) iddlgshow = dlgGetNewId();

        var url = "?page=list&pagesub=employee&datastruct=c";
        var dataString = "";
        jQuery.ajax({
            url: url,
            data: dataString,
            type: "GET",
            success: function (data) {
                data = getDataOk(data);
                var strout = DlgSelect.formatDataAsGrid(data, ds_employee_c, fnCallBackName, fnCallBackParams);
                strout += "<input type=\"button\" class=\"btndlg default\" style=\"width:50%\" value=\"Bỏ chọn\" onclick=\"dlgRemove();" + fnCallBackName + "(" + arrayToStringAsList(fnCallBackParams) + ");\">";
                strout += "<input type=\"button\" class=\"btndlg cancel\" style=\"width:50%\" value=\"Đóng\" onclick=\"dlgRemove();\">";
                dlgShow(strout, itxt("chonnhanvien"), iddlg);
                UiControl.inputWithClearButtonSetup();
                //setFocus("scontactname");
            },
            error: function () {
                hideModal();
            }
        });
    }
    static showGoodsColor(fnCallBack, arParams) {
        var url = "?page=list&pagesub=color";
        var dataString = "";
        jQuery.ajax({
            url: url,
            data: dataString,
            type: "GET",
            success: function (data) {
                data = getDataOk(data);
                var strout = DlgSelect.formatAsDataGrid2(data, fnCallBack, arParams, "Chọn");
                strout += "<input type=\"button\" class=\"btndlg cancel\" style=\"width:100%\" value=\"Đóng\" onclick=\"dlgRemove();\">";
                dlgShow(strout);
            },
            error: function () {
                hideModal();
            }
        });
    }

}
//END:UIListBoxEx
//*START_CLASS_GRID_VIEW_EX
class GridViewEx {
    //var data_struct=[
    //	{name:"id",head:"",visible:0,idsub:1/2..},
    //	{name:"name/data.."  ,head:"HEAD",visible:0/1/2,type:"text/check/number",required:1/0,merge:"1"},
    //];
    //row_id: tao tu vals[0], val[0] la so hoac la text, co the combine tu server de unique
    //idsub: thu tu phan tu chua du lieu them vao phan tu [0] de dam bao duy nhat, khi 1 row co id trung voi row truoc do (hang nhieu dvt)
    //visible:0-hidden, 1-show, 2-select option, 3-not visible in grid, but on add/edit;
    //viewname: ten cua truong gia tri se duoc cap nhat khi select thay doi (ap dung cho visible=2), trong form edit/add
    //merge: 1-merge khong hien thi neu gia tri trung voi phan tu tuong ung row truoc
    //head: neu de rong se khong hien thi
    //readonly: 1 - chi doc, khong sua khong them
    //editable: 0 - co hien thi khong sua doi, 1-co the sua doi

    /*android khong cho khai bao bien ngoai ham dung
    objInstanceName='';//ten cua doi tuong duoc tao ra tu lop, de goi cac phuong thuc
    data_struct=null;
    page_source="";
    page_title="";
    grid_caption="";
    show_collapsiblerow=0;
    editfrom_header="";//current edit from, is showing
    editform_content="";
    editfrom_firstfocus="";
    m_fnCmd=null;
    m_fnCmdTitle=null;
    m_fnCmdParams=null;
    m_fnCallBackCheckCellEditable=null;//check 1 row du lieu cu the, 1 cell cu the co cho phep editable hay khong
    m_fnCallBackOnClick=null;//click on row
    m_fnCallBackOnClickCell=null;//click on cell
    active_param=null;//save something
    viewmode="grid";//grid,list,collapselist,collapsegrid
    onClickItem(id)
    bItemMultiRow: moi row gom 1 hang chinh voi cac cell va cac hang phu 1 cell
    idrowprefix: them vao truoc id row de duy nhat vi cung 1 data co the hien thi trong cac div, block khac nhau
    m_arExtraButtons=[{caption:"caption",function:"functionCallBack",class:"style_class"}]
    rowheading_visible: xac dinh visible nao lam tieu de
    */
    constructor(in_data_struct, objectInstanceName, in_page_source) {
        this.data_struct = in_data_struct;
        this.data_rows = null;
        this.objInstanceName = objectInstanceName;//ten bien global scope cua doi tuong duoc tao ra
        this.page_source = in_page_source;
        this.idrowprefix = "";
        this.updateable = null;
        this.viewmode = null;
        this.collapsible = false;
        this.collapsibleall = false;//all row collapsible
        this.nFirstVisibledCell = -1;
        this.nLastVisibledCell = -1;
        this.nExtraButtonCount = 0;
        for (var i = 0; i < this.data_struct.length; i++) {
            if (dsIsVisible(this.data_struct, i)) {
                if (this.nFirstVisibledCell < 0) this.nFirstVisibledCell = i;
                this.nLastVisibledCell = i;
            }
        }
        this.rowheading_visible = 1;
        this.viewmode = "grid";
        this.classHeadingRow = "";
        this.classHeadingCell = "";
    }
    getDataFromIdAndColumnName(id, strColumnName) {
        var type = dsGetType(this.data_struct, strColumnName);
        var idcell = this.getCellId(strColumnName, id);
        var cell = document.getElementById(idcell);
        if (cell == null) {
            return '';
        }
        if (type == "check") {
            if (cell.innerHTML.length > 0) { return 1; }
            else {
                return 0;
            }
        }
        var value = cell.value;//khong phai la input, noi dung cua div hoac td
        if (isEmpty(value)) value = cell.innerHTML;
        if (isEmpty(value)) return '';
        return value;
    }

    getDataFromId(id, idsub) {
        var data_vals = [];
        data_vals[0] = id;
        for (i = 1; i < this.data_struct.length; i++) {
            var cellid = this.getCellId(this.data_struct[i].name, id, idsub);
            var cell = document.getElementById(cellid);
            if (isEmpty(cell)) {
                data_vals[i] = "";
                continue;//co the ghep cac field
            }
            if (dsIsVisible(this.data_struct, i)) {
                if (this.data_struct[i].editable == 1)
                    data_vals[i] = cell.value;
                else
                    data_vals[i] = (cell.innerHTML);
            }
            else {
                data_vals[i] = (cell.value);
            }
        }
        return data_vals;
    }
    //de dam bao cau truc, neu field nao khong hien dien trong form
    //nhung van co trong data_struct se duoc gan trong
    //du lieu number convert ve dang du lieu so, khong phai dang hien thi
    getDataFromForm(f) {
        var data_vals = [];
        data_vals[0] = "0";
        for (i = 1; i < this.data_struct.length; i++) {
            if (isEmpty(f.elements.namedItem(this.data_struct[i].name))) {
                data_vals[i] = "";
                continue;
            }
            if (this.data_struct[i].type == "check") {
                if (this.data_struct[i].readonly == 1) {
                    if (f.elements.namedItem(this.data_struct[i].name).value != "")
                        data_vals[i] = "1";
                    else
                        data_vals[i] = "";
                }
                else {
                    if (f.elements.namedItem(this.data_struct[i].name).checked)
                        data_vals[i] = "1";
                    else
                        data_vals[i] = "";
                }
            }
            else {
                data_vals[i] = f.elements.namedItem(this.data_struct[i].name).value;
                if (this.data_struct[i].type == "number") {
                    data_vals[i] = parseNumberVn(data_vals[i]);
                }
                if (this.data_struct[i].required == 1) {
                    if (data_vals[i].length < 1) {
                        //return false;
                    }
                }
            }

        }

        return data_vals;
    }
    getRowHeadingId() {
        return "idrowheading" + this.data_struct[0].name;
    }
    //idsub neu co phai >0: goods -> units
    getRowId(id, idsub) {
        var idrow = id;
        if (!isEmpty(idsub)) {
            if (parseInt(idsub) > 0)
                idrow += gIdCombineChar + idsub;
        }
        if (!isEmpty(this.idrowprefix))
            idrow = this.idrowprefix + gIdCombineChar + idrow;
        return "idrow" + this.data_struct[0].name + idrow;
    }
    getRowIdMainCollapsiable(id) {
        return this.getRowId(id) + "main";
    }
    getRowIdSubCollapsiable(id) {
        return this.getRowId(id) + "sub";
    }
    getCellId(col_name, id, idsub) {
        var cellid = col_name;
        if (!isEmpty(this.idrowprefix)) cellid += this.idrowprefix;
        cellid += id;
        if (!isEmpty(idsub)) cellid += gIdCombineChar + idsub;
        return cellid;
    }
    //data_vals: array of value current row, j:position of value (cell)
    getSubInfoValue(data_vals, j) {
        var subinfobreak = "";
        if (isEmpty(this.data_struct[j].subinfobreak))
            subinfobreak = "<br>";
        else
            subinfobreak = this.data_struct[j].subinfobreak;
        var subinfo = "";
        if (Array.isArray(this.data_struct[j].subinfo)) {
            for (var n = 0; n < this.data_struct[j].subinfo.length; n++) {
                var subindex = this.data_struct[j].subinfo[n];
                subinfo += subinfobreak;
                subinfo += data_vals[subindex];
            }
        }
        else {
            subinfo += subinfobreak;
            subinfo = data_vals[this.data_struct[j].subinfo];
        }
        return "<span class='subinfo italic'>" + subinfo + "</span>";
    }
    // item kieu select, co gia tri nam trong 1 array [id,text]
    // i: index cua item trong struct dinh nghia
    // value: gia tri cua id
    getItemSelectText(i, value) {
        var ret = "";
        var sdata;
        if (isString(this.data_struct[i].data)) sdata = eval(this.data_struct[i].data);
        else sdata = this.data_struct[i].data;

        for (var k = 0; k < sdata.length; k++) {
            //neu sdata la array
            if (Array.isArray(sdata[k])) {

                if ((value == sdata[k][0]) || (value == sdata[k][1]))
                    return sdata[k][1];
            } else if (isObject(sdata[k])) {
                if ((value == sdata[k].id) || (value == sdata[k].name))
                    return sdata[k].name;
            }
            else {
                if (value == sdata[k])
                    return sdata[k];
            }
        }
        return "";
    }
    //list_view
    genRowList(data_vals, genoutsideHTML) {
        var id = "", idrow = "", cmd = "";
        id = data_vals[0];
        idrow = this.getRowId(data_vals[0]);
        var label = "";
        var row = "";
        if (genoutsideHTML)
            row += "<div class='list_item' style='margin-bottom:1px;padding:4px' id='" + idrow + "'>";

        for (var j = 1; j < data_vals.length; j++) {
            if (dsIsVisible(this.data_struct, j)) {
                if (label != "") {
                    label += "<br>&nbsp;";
                    label += "<span>" + this.data_struct[j].head + ": <span id='" + this.getCellId(this.data_struct[j].name, data_vals[0]) + "'>" + data_vals[j] + "</span></span>";
                }
                else {
                    label += "<b><span id='" + this.getCellId(this.data_struct[j].name, data_vals[0]) + "'>" + data_vals[j] + "</span></b>";
                }
            }
            else {
                label += "<input type='hidden' id='" + this.getCellId(this.data_struct[j].name, data_vals[0]) + "' value='" + data_vals[j] + "'>";
            }
        }
        var buttons = "";
        if (Array.isArray(this.m_arExtraButtons)) {
            for (var k = 0; k < this.m_arExtraButtons.length; k++) {
                buttons += "<input type='button' class='collapsibleheaderbutton' style='float:right' value='" + this.m_arExtraButtons[k].caption + "' onclick=\"" + this.m_arExtraButtons[k].function + "(" + data_vals[0] + ");event.stopPropagation()\">";
            }
        }
        label = buttons + label;
        if (genoutsideHTML) {
            row += label;
            row += "</div>";
            row += "<div class='collapsiblecontent' id='" + idrow + "sub'></div>";
            return row;
        }
        return label;
    }
    showGridCollapsible_GenRow(data_vals, genoutsideHTML) {
        var idrowmain = this.getRowIdMainCollapsiable(data_vals[0]);
        var idrowsub = this.getRowIdSubCollapsiable(data_vals[0]);
        var idsub = this.getIdSub(data_vals);
        //ITEM_START

        //cells-start
        var cells = "";
        for (var j = 1; j < data_vals.length; j++) {
            var cellid = this.getCellId(this.data_struct[j].name, data_vals[0], idsub);
            var value = data_vals[j], style_width = "";
            if (dsIsVisible(this.data_struct, j)) {
                var style = "";
                if (this.data_struct[j].type == "number") {
                    style += ";text-align:right;justify-content: right;";
                    value = formatNumberZS(value);
                }
                //duoi nhu %
                if ((value.length > 0) && (!isEmpty(this.data_struct[j].subfix))) {
                    value = value + this.data_struct[j].subfix;
                }
                if (!isEmpty(dsGetWidth(this.data_struct, j))) {
                    if (j == this.nLastVisibledCell)
                        style_width = ";width:calc(" + dsGetWidth(this.data_struct, j) + " - " + (this.nExtraButtonCount * parseNumberVn(g_ui_cmdwidth)) + "px)";
                    else
                        style_width = ";width:" + dsGetWidth(this.data_struct, j);
                    style += style_width;
                }

                //thong tin phu
                var cellsubinfo = "";
                if (!isEmpty(this.data_struct[j].subinfo)) {
                    var subinfo = "", sclass = "", svalue = "";
                    for (var n = 0; n < this.data_struct[j].subinfo.length; n++) {
                        var subindex = this.data_struct[j].subinfo[n];
                        if (isEmpty(this.data_struct[subindex].subinfobreak))
                            subinfo += "<br>";
                        else
                            subinfo += this.data_struct[subindex].subinfobreak;
                        svalue = data_vals[subindex];
                        if (this.data_struct[subindex].type == "number") svalue = formatNumberZS(svalue);
                        if ((svalue.length > 0) && (!isEmpty(this.data_struct[subindex].subfix))) {
                            svalue = svalue + this.data_struct[subindex].subfix;
                        }

                        if (!isEmpty(this.data_struct[subindex].subinfoclass)) sclass = this.data_struct[subindex].subinfoclass;
                        if (!isEmpty(this.data_struct[subindex].class)) sclass = this.data_struct[subindex].class;
                        var scellid = this.getCellId(this.data_struct[subindex].name, data_vals[0], idsub);
                        subinfo += "<span id='" + scellid + "' class='" + sclass + "'>" + svalue + "</span>";
                    }
                    if (!isEmpty(this.data_struct[j].subinfoclass))
                        subinfo = "<span class='" + this.data_struct[j].subinfoclass + "'>" + subinfo + "</span>";
                    cellsubinfo = subinfo;
                }
                //first pin image
                var cellClass = "divcell";
                if (j == this.nFirstVisibledCell) {
                    cellClass += " collapsible";
                }
                cells += "<div class='" + cellClass + "' style='" + style + "'>";
                cells += "<span class='" + this.data_struct[j].maininfoclass + "' id='" + cellid + "'>" + value + "</span>";
                cells += cellsubinfo;
                cells += "</div > ";
            }
            else {
                cells += "<input type='hidden' id='" + cellid + "' value='" + (value) + "'>";
            }
        }
        //cells_end
        var buttons = "";
        if (Array.isArray(this.m_arExtraButtons)) {
            for (var k = 0; k < this.m_arExtraButtons.length; k++) {
                var classBt = this.m_arExtraButtons[k].class;
                if (isEmpty(classBt)) classBt = "gridcell cmd";
                buttons += "<a href=\"javascript:void(0)\" class=\"" + classBt + "\" style=\"float:right;width:" +
                    g_ui_cmdwidth + "px;\" onclick=\"event.stopPropagation();" +
                    this.m_arExtraButtons[k].function + "(";
                for (var pr = 0; pr < data_vals.length; pr++) {
                    buttons += "'" + escapeJS(data_vals[pr]) + "',";
                }
                buttons += ");\" title=\"" + this.m_arExtraButtons[k].promt + "\">" + this.m_arExtraButtons[k].caption + "</a>";
            }
        }

        //cells-end
        var row = "<div class=\"list_item collapsible\" style=\"overflow-y:auto;height:auto;\"  id=\"" + idrowmain
            + "\" onclick=\"event.stopPropagation();divToggle('" + idrowmain + "','" + idrowsub + "',"
            + escapeHTML(this.m_fnCallBackOnExpand) + "('" + idrowsub + "','" + data_vals[0] + "'))\">";
        row += "<div class='divtable'>";
        row += "<div class='divrow'>";
        row += cells;
        if (buttons.length > 0)
            row += "<div class='divcell' style='padding:0px;border-radius:0px 8px 0px 0px;width:" + this.nExtraButtonCount * parseNumberVn(g_ui_cmdwidth) + "px;'>" + buttons + "</div>";
        row += "</div>";
        row += "</div>";

        //expand part of row
        row += "<div class='list_item collapsiblecontent' id='" + idrowsub + "'></div>";
        row += "</div>";

        //ITEM_END
        return row;
    }
    //hang phia duoi hang chinh
    genRow_Sub(data_vals, bkeepselectval) {
        var row = "";
        for (var j = 1; j < data_vals.length; j++) {
            if (!isEmpty(this.data_struct[j].rowsub) && (this.data_struct[j].rowsub > 0)) {
                if (data_vals[j].length > 0) {
                    //du lieu la cau truc
                    if (!isEmpty(this.data_struct[j].rowsub_ds)) {
                        var goods = data_vals[j].split(g_split_group);
                        var ds = this.data_struct[j].rowsub_ds;
                        if (isEmpty(ds)) {
                            alert("rowsub datastruct not specified!"); return;
                        }
                        var col_lastvisible = dsGetLastVisible(ds);
                        for (var g = 0; g < goods.length; g++) {
                            var vals = goods[g].split(g_split_groupsub);
                            row += "<span style='width:100%;padding:4px 0px;display:block;border-bottom:1px dotted lightgrey; height:auto;overflow-y:auto;'>";
                            for (var v = 0; v < vals.length; v++) {
                                if (ds[v].visible == 1) {
                                    if (v == col_lastvisible)
                                        row += "<span style='width:" + ds[v].width + ";float:right;text-align:right;'>" + vals[v];
                                    else
                                        row += "<span style='width:" + ds[v].width + ";float:left'>" + vals[v];
                                    if (Array.isArray(ds[v].subinfo)) {
                                        for (var s = 0; s < ds[v].subinfo.length; s++) {
                                            row += ds[ds[v].subinfo[s]].subinfobreak;
                                            if (ds[ds[v].subinfo[s]].type == "number")
                                                row += formatNumberZS(vals[ds[v].subinfo[s]]);
                                            else
                                                row += (vals[ds[v].subinfo[s]]);
                                        }
                                    }
                                    row += "</span>";
                                }
                            }
                            row += "</span>";
                        }
                    } else {
                        row += data_vals[j];
                        for (var s = 0; s < this.data_struct[j].rowsub; s++)row += "<br>";
                    }

                }
            }
        }
        if (row.length > 0) {
            row = "<div class='divcellmultirowdown'>" + row + "</div>";
        }

        return row;
    }
    genRowHeading(classRow, classCell, nExtraButtonCount) {
        if (isEmpty(nExtraButtonCount)) {
            if (Array.isArray(this.m_arExtraButtons))
                nExtraButtonCount = this.m_arExtraButtons.length;
            else
                nExtraButtonCount = 0;
        } else {
            nExtraButtonCount = 0;
        }

        var rowheading = "";
        if (this.viewmode == "gridex") {
            rowheading += "<tr class='heading' id='" + this.getRowHeadingId() + "'>";
            for (var i = 1; i < this.data_struct.length; i++) {
                if (dsIsVisible(this.data_struct, i)) {
                    var style = "", head = this.data_struct[i].head;
                    if (!isEmpty(dsGetWidth(this.data_struct, i))) style += "width:" + dsGetWidth(this.data_struct, i);
                    if (this.data_struct[i].type == "number") style += ";text-align:right";
                    if (Array.isArray(this.data_struct[i].subinfo)) {
                        var arrSIF = this.data_struct[i].subinfo;
                        for (var sif = 0; sif < arrSIF.length; sif++) {
                            head += "/" + this.data_struct[arrSIF[sif]].head;
                        }
                    }
                    if (this.bItemMultiRow) {
                        rowheading += "<td class='heading' style='" + style + "'>" + head + "</td>";
                    } else {
                        rowheading += "<td class='heading' style='" + style + "'>" + head + "</td>";
                    }
                }
            }
            rowheading += "</tr>";
        } else if (this.viewmode == "list") {
            if (!isEmpty(this.grid_caption)) {
                rowheading = "<div class='list_item title'>";
                rowheading += "<span style='width:calc(100% - " + g_ui_cmdwidth + "px);'>" + this.grid_caption + "</span>";
                rowheading += '<span class="buttonincell addimage" style="float:right;width:' + g_ui_cmdwidth + 'px;" onclick=""></span>';
                rowheading += "</div>";
            }
        }
        else {
            if (isEmpty(classRow)) classRow = "divrow heading";
            if (isEmpty(classCell)) classCell = "divcell";

            this.nFirstVisibledCell = -1;
            this.nLastVisibledCell = -1;
            for (var i = 0; i < this.data_struct.length; i++) {
                if (dsIsVisible(this.data_struct, i)) {
                    if (this.nFirstVisibledCell < 0) this.nFirstVisibledCell = i;
                    this.nLastVisibledCell = i;
                }
            }

            rowheading += "<div class='" + classRow + "' id='" + this.getRowHeadingId() + "'>";
            for (var i = 1; i < this.data_struct.length; i++) {
                if (!isEmpty(this.data_struct[i].rowsub)) continue;
                if (!isEmpty(this.rowheading_visible)) {
                    if (dsGetVisible(this.data_struct, i) != this.rowheading_visible) continue;
                }
                if (dsGetVisible(this.data_struct, i) > 0) {

                    var style = "", head = this.data_struct[i].head;
                    if (Array.isArray(this.data_struct[i].subinfo)) {
                        var arrSIF = this.data_struct[i].subinfo;
                        for (var sif = 0; sif < arrSIF.length; sif++) {
                            var sifClass = "";
                            if (!isEmpty(this.data_struct[arrSIF[sif]].class)) sifClass = this.data_struct[arrSIF[sif]].class;
                            head += "/<span class='" + sifClass + "'>" + this.data_struct[arrSIF[sif]].head + "</span>";
                        }
                    }
                    if (!isEmpty(dsGetWidth(this.data_struct, i))) {
                        if (i == this.nLastVisibledCell) {
                            style += ";width:calc(" + dsGetWidth(this.data_struct, i) + " - " + (nExtraButtonCount * parseNumberVn(g_ui_cmdwidth)) + "px)";

                        }
                        else
                            style += ";width:" + dsGetWidth(this.data_struct, i);
                    }
                    if (this.data_struct[i].type == "number") style += ";text-align:right;justify-content:center";
                    var tipFn = "";
                    if (!isEmpty(this.data_struct[i].tip)) tipFn = "onclick='showMsg(\"" + escapeHTML(this.data_struct[i].tip) + "\")'";
                    if (this.bItemMultiRow) {
                        rowheading += "<span " + tipFn + " class='" + classCell + "multirowup' style='cursor:pointer;" + style + "'>" + head + "</span>";
                    } else {
                        rowheading += "<div " + tipFn + " class='" + classCell + "' style='cursor:pointer;" + style + "'>" + head + "</div>";
                    }
                }
            }

            //hang hien thi khong phai hang dau, khong chua nut
            if (isEmpty(this.rowheading_visible) || nExtraButtonCount > 0) {
                if (nExtraButtonCount > 0) {
                    if (this.bItemMultiRow) {
                        rowheading += "<span style='width:" + (nExtraButtonCount * parseNumberVn(g_ui_cmdwidth)) + "px;'></span>";
                    } else {
                        rowheading += "<div class='" + classCell + "' style='width:" + (nExtraButtonCount * parseNumber(g_ui_cmdwidth)) + "px;'></div>";
                    }
                }
            }

            rowheading += "</div>";
        }
        return rowheading;
    }


    saveForm(f, iddivshowitem = null, updategridview = 1, fnCallBackNewRecordData = null) {

        var editformtype = f.elements.namedItem("editformtype").value;
        var currentviewmode = f.elements.namedItem("currentviewmode").value;
        var data_vals = this.getDataFromForm(f);
        var label = "";
        if (isEmpty(iddivshowitem)) iddivshowitem = this.m_idContent;
        var arSelectVal = [];
        var arSelectName = [];
        for (i = 0; i < this.data_struct.length; i++) {
            if ((label.length == 0) && (dsIsVisible(this.data_struct, i))) label = data_vals[i];
            if (this.data_struct[i].required == 1) {
                if (data_vals[i].length < 1) {
                    showModalUpdateHeader(this.data_struct[i].head + ": " + itxt("khongduocdetrong"));
                    return false;
                }
            }
            //keep select val to remain status
            if (this.data_struct[i].type == "select") {
                arSelectVal[arSelectVal.length] = f[this.data_struct[i].name].value;
                arSelectName[arSelectName.length] = this.data_struct[i].name;
            }
        }
        var form = $(f);
        var idForm = form.attr("id");
        var url = form.attr('action');
        var dataString = form.serialize();
        var outThis = this;//goi ajax khong dong bo, khong con nam trong pham vi doi tuong nua

        jQuery.ajax({
            url: url,
            data: dataString,
            type: "POST",
            success: function (data) {
                if (!isDataOk(data)) {
                    showMsg([itxt("thatbai"), getDataFail(data)]);
                    return false;
                }
                var newid = parseNumberVn(getDataOk(data));
                if (parseInt(newid) <= 0) {
                    showMsg(itxt("thatbai"));
                    return false;
                }
                data_vals[0] = newid;

                if (updategridview == 1) {
                    //xu ly rieng showGridUpdateble
                    if (currentviewmode == "grid" && outThis.updateable == 1) {
                        if (editformtype == "edit") {
                            outThis.showGridUpdateable_UpdateRow(data_vals);
                            hideModalBlock();
                        } else {
                            outThis.showGridUpdateable_AddRow(data_vals);
                            //add_more
                            showModalBlock(outThis.editform_content, "Đã thêm: " + label);
                            //restore select
                            var newform = document.getElementById(idForm);
                            for (var s = 0; s < arSelectName.length; s++) {
                                newform[arSelectName[s]].value = arSelectVal[s];
                            }
                        }

                    } else {
                        var iditem = null;
                        var row = "";
                        if (currentviewmode == "list") {
                            if (outThis.collapsible)
                                row = outThis.showGridCollapsible_GenRow(data_vals, (editformtype == "add"));
                            else
                                row = outThis.genRowList(data_vals, (editformtype == "add"));
                        } else if ((currentviewmode == "grid") || (currentviewmode == "gridex")) {
                            if (outThis.collapsible)
                                row = outThis.showGridCollapsible_GenRow(data_vals, (editformtype == "add"));
                            else {
                                row = outThis.showGrid_GenRow(data_vals, true);
                            }
                        }
                        if (editformtype == "edit") {
                            if (outThis.collapsible)
                                iditem = document.getElementById(outThis.getRowIdMainCollapsiable(newid));
                            else
                                iditem = document.getElementById(outThis.getRowId(newid));
                            if (!isEmpty(iditem)) {
                                iditem.innerHTML = row;
                            }
                            hideModalBlock();
                        } else if (editformtype == "add") {
                            var iditem = null;
                            //co the co nhieu heading neu dinh dang hien thi collapse, tim row heading thuoc ve div nay
                            if (currentviewmode != "grid") {
                                if (isString(iddivshowitem)) iddivshowitem = document.getElementById(iddivshowitem);
                                if (!isEmpty(iddivshowitem)) iddivshowitem.innerHTML = iddivshowitem.innerHTML + row;
                            }
                            else {
                                iditem = outThis.findRowheadingInTable(iddivshowitem);
                                if (iditem === null)
                                    iditem = document.getElementById("idrowheading");
                                if (iditem != null)
                                    iditem.outerHTML = iditem.outerHTML + row;
                            }
                            //add_more
                            showModalBlock(outThis.editform_content, "Đã thêm: " + label);
                            //restore select
                            var newform = document.getElementById(idForm);
                            for (var s = 0; s < arSelectName.length; s++) {
                                newform[arSelectName[s]].value = arSelectVal[s];
                            }

                        }
                    }

                }
                else {
                    hideModalBlock();
                }
                if (!isEmpty(fnCallBackNewRecordData)) {
                    if (isString(fnCallBackNewRecordData)) {
                        execFn(fnCallBackNewRecordData, data_vals);
                    }
                    else {
                        fnCallBackNewRecordData.apply(this, data_vals);
                    }
                    return false;
                }
                return false;
            },
            error: function () {
                hideModalBlock();
                showMsg(itxt("thatbai"), outThis.title);
            }
        });
        return false;
    }
    showItemDetails(id, idsub, bshow = true) {
        var data_vals = this.getDataFromId(id, idsub);
        var html = "<div class='divtable'>";
        for (var i = 0; i < this.data_struct.length; i++) {
            if (isEmpty(this.data_struct[i].head)) continue;
            html += "<div class='divrow'>";
            html += "<div class='divcell' style='width:30%'>" + this.data_struct[i].head + "</div>";
            if (this.data_struct[i].type == "select")
                html += "<div class='divcell'>" + this.getItemSelectText(i, data_vals[i]) + "</div>";
            else
                html += "<div class='divcell'>" + data_vals[i] + "</div>";
            html += "</div>";
        }
        html += "</div>";
        if (bshow)
            showModal(html);
        else
            return html;
    }

    showDetails(id, idsub, bshow = true) {
        return this.showItemDetails(id, idsub, bshow);
    }
    //id==0:add,>0:edit
    //updategridview 0/1: update change value for view if viewed
    //fnCallBackNewRecordData: call back function with new data
    //neu fnSubmit se su dung cho form
    showEditForm(ids, extrafieldvalue = null, iddivshowitem = "", rowdata = null, updategridview = 1, fnCallBackNewRecordData) {

        var id = '', idsub = '';
        if (Array.isArray(ids)) {
            if (ids.length == 2) {
                id = ids[0];
                idsub = ids[1];
            } else {
                id = ids[0];
                idsub = null;
            }
        } else {
            id = ids;
            idsub = '';
        }
        //extrafieldvalue [{name,value}] => [{name:"a",value:1}]
        //iddivshowitem: div chua danh sach item
        this.editfrom_firstfocus = "";
        var i = 0;
        var html = "", type = "", checkstatus = "", prompt = "", firstinputname = "";
        var data_vals = [];

        if (!isEmpty(rowdata)) {
            data_vals = rowdata.split(g_split_val);
            id = data_vals[0];
            if (parseInt(id) > 0) {
                type = "edit";
            }
            else {
                type = "add";
            }
        }
        else {
            if (parseInt(id) > 0) {
                data_vals = this.getDataFromId(id, idsub);
                type = "edit";
            } else {
                data_vals = null;
                type = "add";
            }
        }

        var idform = "idformgridedit" + id;

        //this.objInstanceName
        if (!isEmpty(fnCallBackNewRecordData))
            html += "<form id='" + idform + "' method='POST' action='?page=" + this.page_source + "' onsubmit='return " + this.objInstanceName + ".saveForm(this,\"" + iddivshowitem + "\"," + updategridview + ",\"" + fnCallBackNewRecordData + "\")' accept-charset='UTF-16'>";
        else
            html += "<form id='" + idform + "' method='POST' action='?page=" + this.page_source + "' onsubmit='return " + this.objInstanceName + ".saveForm(this,\"" + iddivshowitem + "\"," + updategridview + ",)' accept-charset='UTF-16'>";

        if (Array.isArray(extrafieldvalue)) {
            for (i = 0; i < extrafieldvalue.length; i++) {
                html += "<input type=\"hidden\" name=\"" + extrafieldvalue[i].name + "\" value=\"" + escapeHTML(extrafieldvalue[i].value) + "\" />";
            }

        }
        html += "<input type='hidden' name='editformtype' value='" + type + "' />";
        html += "<input type='hidden' name='currentviewmode' value='" + this.viewmode + "' />";

        html += "<input type='hidden' name='" + this.data_struct[0].name + "' value='" + id + "' />";
        html += "<div class='divtable'>";
        for (i = 1; i < this.data_struct.length; i++) {
            var name = this.data_struct[i].name;
            var value = "";
            if (dsGetVisible(this.data_struct, i) == 0) {
                if (!isEmpty(data_vals))
                    value = data_vals[i];
                else
                    value = "";
                html += "<input type=\"hidden\" name=\"" + name + "\" value=\"" + escapeHTML(value) + "\">";
                continue;
            }
            if (this.data_struct[i].readonly == 1) {
                if (!isEmpty(data_vals))
                    value = data_vals[i];
                else
                    value = "";
                html += "<input type='hidden' name=\"" + name + "\" value=\"" + escapeHTML(value) + "\">";
                continue;
            }

            if (this.data_struct[i].prompt !== undefined) {
                prompt = "<span style='line-height:150%'>" + escapeHTML(this.data_struct[i].prompt) + "</span>";

            }
            else
                prompt = "";

            html += "<div class='divrow'>";
            value = this.data_struct[i].head;

            if (this.data_struct[i].required == 1) {
                value += "*";
            }
            html += "<div class='divcell' style='width:%'>" + value + "</div>";
            value = "";
            if (!isEmpty(data_vals))
                value = data_vals[i];
            else
                value = "";

            //che do sua doi, hien thi truong khong the cap nhat editable=0
            if ((this.data_struct[i].editable == 0) && (id > 0)) {
                html += "<input type='hidden' name=\"" + name + "\" value=\"" + escapeHTML(value) + "\">";
                html += "<div class='divcell' style='width:%'>" + escapeHTML(value) + "</div>";
            }
            else if (this.data_struct[i].type == "check") {
                if (!isEmpty(data_vals)) {
                    if (data_vals[i] != "")
                        checkstatus = "checked";
                    else
                        checkstatus = "";
                }
                else
                    checkstatus = "";
                value = "on";
                html += "<div class='divcell'><input type='checkbox' name='" + name + "' value='" + escapeHTML(value) + "' " + checkstatus + " >" + prompt + "</div>";
            }
            else if (this.data_struct[i].type == "number") {
                html += "<div class='divcell'><input type='text' onfocus='this.select()' onkeyup='return fi_doFormat(this)' name='" + name + "' value='" + escapeHTML(value) + "'  style='width:100%;'>" + prompt + "</div>";

            }
            else if (this.data_struct[i].type == "select") {
                var ops = "", select = "";
                var sdata;
                if (isString(this.data_struct[i].data)) sdata = eval(this.data_struct[i].data);
                else sdata = this.data_struct[i].data;

                for (var k = 0; k < sdata.length; k++) {
                    //neu sdata la array
                    if (Array.isArray(sdata[k])) {

                        if ((value == sdata[k][0]) || (value == sdata[k][1]))
                            ops += "<option value=\'" + sdata[k][0] + "' selected>" + escapeHTML(sdata[k][1]) + "</option>";
                        else
                            ops += "<option value=\'" + sdata[k][0] + "'>" + escapeHTML(sdata[k][1]) + "</option>";
                    } else if (isObject(sdata[k])) {
                        if ((value == sdata[k].id) || (value == sdata[k].name))
                            ops += "<option value=\'" + sdata[k].id + "' selected>" + escapeHTML(sdata[k].name) + "</option>";
                        else
                            ops += "<option value=\'" + sdata[k].id + "'>" + escapeHTML(sdata[k].name) + "</option>";
                    }
                    else {
                        if (value == sdata[k])
                            ops += "<option value=\'" + sdata[k] + "' selected>" + escapeHTML(sdata[k]) + "</option>";
                        else
                            ops += "<option value=\'" + sdata[k] + "'>" + escapeHTML(sdata[k]) + "</option>";
                    }
                }
                if (this.data_struct[i].required != 1)
                    ops = "<option value=></option>" + ops;

                select = "<select size='1' name='" + name + "' style='width:100%'";
                if (!isEmpty(this.data_struct[i].viewname))
                    select += " onchange='this.form." + this.data_struct[i].viewname + ".value=getSelectText(this);'";
                select += ">" + ops + "</select>";
                html += "<div class='divcell'>" + select + "</div>";

            }
            else {
                html += "<div class='divcell'><input type='text'  onfocus='this.select();' name='" + name + "' value=\"" + escapeHTML(value) + "\" style='width:100%;'>" + prompt + "</div>";
            }
            if (this.data_struct[i].prompt !== undefined) {

            }
            html += "</div>";
        }

        html += "</div>";
        html += "<input type=\"button\" class=\"btndlg cancel\" style=\"width:50%\" value=\"Đóng\" onclick=\"hideModalBlock(false)\">";
        html += "<input type=\"submit\" class=\"btndlg ok\" style=\"width:50%\" value=\"Ghi\">";
        html += "</form>";

        var dlgheader = this.editfrom_header;
        if (isEmpty(dlgheader)) {
            if (type == "edit") dlgheader = itxt("sua");
            else dlgheader = itxt("them");
        }

        //save current edit from for new add
        if (type == "add") {
            this.editform_content = html;
        }

        showModalBlock(html, dlgheader);
        $('form:first *:input[type!=hidden]:first').focus();
        return idform;
    }
    //chi xoa hien thi
    removeRowView(id, idsub) {
        var idrow = this.getRowId(id, idsub);
        var iditem = document.getElementById(idrow);
        if (iditem != null) iditem.innerHTML = "";

        var idrowmain = this.getRowIdMainCollapsiable(id);
        idrowmain = document.getElementById(idrowmain);
        if (idrowmain != null) idrowmain.outerHTML = "";

        var idrowsub = this.getRowIdSubCollapsiable(id);
        idrowsub = document.getElementById(idrowsub);
        if (idrowsub != null) idrowsub.outerHTML = "";
    }
    //gui lenh xoa len server, thanh cong se xoa hien thi
    removeRow(id, fnCallBackName) {
        showWaitModal();
        var url = "?page=" + this.page_source + "&pagesub=remove&action=remove&" + this.data_struct[0].name + "=" + id;
        var outThis = this;
        var dataString = "";
        jQuery.ajax({
            url: url,
            data: dataString,
            type: "GET",
            success: function (data) {
                if (isDataOk(data)) {
                    var id = parseNumberVn(getDataOk(data));
                    var idrow = outThis.getRowId(id);
                    var iditem = document.getElementById(idrow);
                    if (iditem != null)
                        iditem.outerHTML = "";
                    var idrowsub = document.getElementById(idrow + "sub");
                    if (idrowsub != null) idrowsub.outerHTML = "";
                    hideModalBlock();
                    if (!isEmpty(fnCallBackName)) {
                        if (isString(fnCallBackName)) {
                            eval(fnCallBackName)();
                        }
                        else {
                            fnCallBackName.apply(this);
                        }

                    }
                }
                else {
                    var mes = getDataFail(data);
                    showMsg([itxt("thatbai"), mes], outThis.page_title);
                    return;
                }
            },
            error: function () {

                showMsg(itxt("thatbai"))
            }
        });

    }
    //return:null/number
    getIdSub(data_vals) {
        if (isEmpty(this.data_struct[0].idsub)) return null;
        var nsub = parseNumberVn(this.data_struct[0].idsub);
        if ((nsub > 0) && (nsub < this.data_struct.length)) {
            return parseNumberVn(data_vals[nsub]);
        }
        return null;
    }
    getAndShow(pageno, idContentlist, fnCallBack, arExtraButtons, url) {
        var outThis = this;//goi ajax khong dong bo, khong con nam trong pham vi doi tuong nua
        if (isEmpty(url))
            url = "?page=" + this.page_source + "&pagesub=list&action=list&pageno=" + pageno;

        var dataString = "";
        jQuery.ajax({
            url: url,
            data: dataString,
            type: "GET",
            success: function (data) {
                if (!isDataOk(data)) {
                    showMsg([itxt("loi"), getDataFail(data)]);
                    return;
                }
                data = getDataOk(data);

                //data,idcontainer,fnCallBackOnExpand,arExtraButtons
                if (outThis.viewmode == "list") {
                    if (this.collapsible)
                        outThis.showListCollapsible((data), idContentlist, fnCallBack, arExtraButtons);
                    else
                        outThis.showList((data), idContentlist, fnCallBack, "", arExtraButtons);
                } else if (outThis.viewmode == "grid") {
                    if (this.collapsible)
                        outThis.showGridCollapsible((data), idContentlist, fnCallBack, arExtraButtons);
                    else {
                        outThis.showGrid((data), idContentlist, fnCallBack);
                    }

                }
                else if (outThis.viewmode == "gridex")
                    outThis.showGridEx((data), idContentlist, fnCallBack);
                hideModalBlock();
            },
            error: function () {
                showMsg(itxt("loi"));
            }
        });
    }
    itemObjectToArray(obj) {
        var data_vals = Array();
        for (var k = 0; k < this.data_struct.length; k++) {
            var valname = this.data_struct[k].name;
            data_vals[k] = obj[valname];
        }
        return data_vals;
    }

    showGridUpdateable_UpdateRow(data_vals) {
        var rowIndex = this.showGridUpdateable_FindRowIndex(data_vals);
        if (rowIndex < 0) {
            showMsg(itxt("khongtimthayhang"));
            return;
        }
        this.data_rows[rowIndex] = Array.from(data_vals);
        var row = this.showGridUpdateable_GenRow(data_vals, rowIndex);
        var bIsMixedRow = this.showGridUpdateable_IsMixedRow(data_vals);
        //hang to hop
        if (bIsMixedRow) {
            var idrowmain = this.getRowIdMainCollapsiable(data_vals[0]);
            setInnerById(idrowmain, row);
        } else {
            var idrow = this.getRowId(data_vals[0]);
            setInnerById(idrow, row);
        }
    }
    showGridUpdateable_UpdateCellByIndex(indexRow, indexCol) {
        var data_vals = this.data_rows[indexRow];
        var prevcellval = null;
        if (indexRow > 0) {
            prevcellval = this.data_rows[indexRow - 1][indexCol];
        }
        var idsub = this.getIdSub(data_vals);
        var bIsMixedRow = this.showGridUpdateable_IsMixedRow(data_vals);//row nay chua prd co materials
        var nExtraButtonCount = Array.isArray(this.m_arExtraButtons) ? this.m_arExtraButtons.length : 0;

        var cell = this.showGridUpdateable_GenCell(data_vals, data_vals[0], idsub, indexRow, bIsMixedRow, indexCol, prevcellval, nExtraButtonCount)

        var cellid = this.getCellId(this.data_struct[indexCol].name, data_vals[0], idsub);
        setOuterById(cellid, cell);
    }
    showGridUpdateable_UpdateCell(idold, rows, data_struct_cell_name) {
        var data_vals;
        if (Array.isArray(rows)) {
            data_vals = rows;

        } else if (typeof (rows) == "object") {
            data_vals = this.itemObjectToArray(rows);
        }
        else
            data_vals = rows.split(g_split_val);

        var idsub = this.getIdSub(data_vals);

        for (var j = 0; j < this.data_struct.length; j++) {
            if (this.data_struct[j].name == data_struct_cell_name) {
                var cellid = this.getCellId(this.data_struct[j].name, idold, idsub);
                setInnerById(cellid, data_vals[j]);
                break;
            }
        }
    }

    //data gom cac data_vals, moi data_vals co data_vals[0]+data_vals[sub] la duy nhat
    //khong quan ly nhieu data_vals[0]+data_vals[sub] trung lap (nhu hoa don co nhieu hang cung 1 loai hang)
    //fnCallBackOnChange(idele, field_name, vals..)
    //fnCallBackOnClick(vals..)
    //fnCallBackOnExpand(iddivshow,vals..)
    showGridUpdateable(data, idcontainer, fnCallBackOnChange, fnCallBackOnClick, fnCallBackOnExpand) {
        if (this.data_rows != null) {
            this.data_rows = [];
            this.data_rows = null;
        }

        this.viewmode = "grid";
        this.updateable = 1;
        this.row_count = 0;
        this.m_idContent = idcontainer;
        this.m_fnCmd = fnCallBackOnClick;
        this.m_fnCallBackOnChange = fnCallBackOnChange;
        this.m_fnCallBackOnExpand = fnCallBackOnExpand;
        this.m_fnCmdTitle = null;
        this.m_fnCmdParams = [];
        this.m_pageno = 0;
        this.m_pagecount = 0;
        this.m_pagesize = 20;
        if (Array.isArray(this.m_arExtraButtons)) this.nExtraButtonCount = this.m_arExtraButtons.length;
        if (!isEmpty(fnCallBackOnExpand)) this.collapsible = true;

        var rowheading = "";
        rowheading = "<div class='divtable'>" + this.genRowHeading(this.classHeadingRow, this.classHeadingCell) + "</div>";

        if (data.length < 1) {
            if (isEmpty(idcontainer)) return rowheading;
            setInnerById(idcontainer, rowheading);
            return;
        }
        var rows = null;
        if (Array.isArray(data))
            rows = data;
        else
            rows = data.split(g_split_row);
        var row_count = rows.length;


        var allrows = "", j = 0, i = 0, startindex = 0;
        if (typeof rows[0] != "object") {
            if (rows[0].substr(0, g_sign_pageconfig.length) == g_sign_pageconfig) {
                var configs = rows[0].split(g_split_val);
                startindex = 1;
                if (configs.length == 3) {
                    this.m_pagesize = parseInt(configs[0]);
                    this.m_pageno = parseInt(configs[1]);
                    this.m_pagecount = parseInt(configs[2]);
                }
            }
        }

        this.row_count = row_count - startindex;
        this.data_rows = [];

        for (var i = startindex; i < row_count; i++) {
            var data_vals = null;
            if (typeof (rows[i]) == "object")
                data_vals = this.itemObjectToArray(rows[i]);
            else
                data_vals = rows[i].split(g_split_val);

            var rowOrderIndex = this.data_rows.length;
            this.data_rows[rowOrderIndex] = Array.from(data_vals);
            var row = this.showGridUpdateable_GenRow(data_vals, rowOrderIndex);
            allrows += row;
        }

        var pageinfo = DlgSelect.getPageIndexSelect(this.m_pageno, this.m_pagecount, "showList");
        if (isEmpty(idcontainer))
            return rowheading + allrows + pageinfo;
        else
            setInnerById(idcontainer, rowheading + allrows + pageinfo);
    }
    showGridUpdateable_AddRow(data) {
        var data_vals;
        if (Array.isArray(data))
            data_vals = data;
        else
            data_vals = data.split(g_split_val);

        var rowOrderIndex = 0;
        this.data_rows = data_vals.concat(this.data_rows);

        this.row_count = this.data_rows.length;
        var allrows = "";
        for (var i = 0; i < this.row_count; i++) {
            allrows += this.showGridUpdateable_GenRow(this.data_rows[i], i);
        }
        var rowheading = "";
        rowheading = "<div class='divtable'>" + this.genRowHeading(this.classHeadingRow, this.classHeadingCell) + "</div>";

        var pageinfo = DlgSelect.getPageIndexSelect(this.m_pageno, this.m_pagecount, "showList");
        setInnerById(this.m_idContent, rowheading + allrows + pageinfo);
    }
    showGridUpdateable_FindRowIndexByFirstId(id) {
        for (var i = 0; i < this.data_rows.length; i++) {
            if (id == this.data_rows[i][0]) {

                return i;
            }
        }
        return -1;
    }
    showGridUpdateable_FindRowIndex(data_vals) {
        var id = data_vals[0];
        var nsub = -1;
        if (!isEmpty(this.data_struct[0].idsub)) {
            nsub = parseNumberVn(this.data_struct[0].idsub);
        }
        for (var i = 0; i < this.data_rows.length; i++) {
            if (data_vals[0] == this.data_rows[i][0]) {
                if (nsub >= 0) {
                    if (data_vals[nsub] == this.data_rows[i][nsub]) {
                        return i;
                    }
                }
                else {
                    return i;
                }
            }
        }
        return -1;
    }
    //row chua prd co materials (collapsible)
    showGridUpdateable_IsMixedRow(data_vals) {
        //cells_start
        var bIsMixedRow = false;
        //mixed
        if (this.collapsibleall) {
            bIsMixedRow = true;
        } else {
            for (var j = 0; j < data_vals.length; j++) {
                if (!isEmpty(this.data_struct[j].mixed) && parseNumberVn(data_vals[j]) > 0) {
                    bIsMixedRow = true;
                    break;
                }
            }
        }
        return bIsMixedRow;
    }

    showGridUpdateable_GenCell(data_vals, id, idsub, rowOrderIndex, bIsMixedRow, cellindex, prevcellval, nExtraButtonCount) {
        var cellid = this.getCellId(this.data_struct[cellindex].name, id, idsub);
        var classCellEx = "";
        var fnOnClickCell = "";
        var value = "", name = "", style = "";
        var cell = "";

        name = this.data_struct[cellindex].name + id;
        value = data_vals[cellindex];

        //first pin image
        if (this.collapsible && cellindex == this.nFirstVisibledCell && bIsMixedRow) {
            style += ";padding-left:" + g_ui_expandsignwidth + "px";
        }
        //first cell
        if (cellindex == this.nFirstVisibledCell) {
            if (!isEmpty(this.m_fnCallBackOnClick)) {
                classCellEx += " click";
            }
        }
        if (this.data_struct[cellindex].type == "number") {
            style += ";text-align:right;justify-content:right;";
            value = formatNumberZS(value);
        }
        var cellwidth = dsGetWidth(this.data_struct, cellindex);
        if (!isEmpty(cellwidth)) {
            if (cellindex == this.nLastVisibledCell) {
                style += ";width:calc(" + cellwidth + " - " + (nExtraButtonCount * parseNumberVn(g_ui_cmdwidth)) + "px)";
            }
            else {

                style += ";width:" + cellwidth;
            }

        }
        if (cellwidth == "100%") style += ";border-bottom: 1px dotted darkgrey;";
        //visible: cell, subinfo, second-row
        var visiblej = dsGetVisible(this.data_struct, cellindex);

        if (visiblej == 1 || visiblej == 2) {
            var celleditable = this.data_struct[cellindex].editable;
            if (this.m_fnCallBackCheckCellEditable != null) {
                celleditable = this.m_fnCallBackCheckCellEditable(data_vals, cellindex);
            }
            if (celleditable) {
                var fOnChange = "";
                var input_width = "100%";
                if (this.collapsible && cellindex == this.nFirstVisibledCell) {
                    input_width = "calc(100% - " + g_ui_expandsignwidth + "px)";
                }
                //vi onchange su dung '' nen fOnChange su dung "" cho cac param
                if (!isEmpty(this.m_fnCallBackOnChange)) {
                    fOnChange = " " + this.m_fnCallBackOnChange + "(this";
                    fOnChange += ",\"" + this.data_struct[cellindex].name + "\"";
                    for (var k = 0; k < data_vals.length; k++) {
                        fOnChange += ",\"" + escapeJS(data_vals[k]) + "\"";
                    }
                    fOnChange += ")";
                }
                if (this.data_struct[this.data_struct.length - 1].name == "in_level" && this.data_struct[this.data_struct.length - 1].type == "in_level") {

                    if (data_vals[this.data_struct.length - 1] > 0 && cellindex == this.nFirstVisibledCell) {
                        style += ";padding-left:12px";
                    }
                }

                cell += "<div class='gridcell padding0' style='" + style + "'>";

                //luu y value: Binh` Bong' - \'8935032704621
                if (this.data_struct[cellindex].type == "number") {
                    cell += "<input type='text' id='" + cellid + "' onclick='event.stopPropagation(); ' class='asdivcell_input' style='text-align: right;width:" + input_width
                        + "' onchange='" + escapeHTML(fOnChange)
                        + "' onfocus='this.select()' onkeyup='return fi_doFormat(this)' name='" + name + "' value='" + (value) + "'>";
                } else {
                    cell += "<input type='text' id='" + cellid + "' onclick='event.stopPropagation(); ' class='asdivcell_input' style='width:" + input_width
                        + "' onchange='" + escapeHTML(fOnChange)
                        + "' onfocus='this.select()' name='" + name + "' value='" + escapeHTML(value) + "'>";
                }
                cell += "</div>";

            }
            else {
                if ((this.data_struct[cellindex].merge == 1) && (prevcellval != null)) {
                    if (data_vals[cellindex] == prevcellval) {
                        value = "";
                    }
                    else {
                        value = data_vals[cellindex];
                    }
                }
                else if (this.data_struct[cellindex].type == "check") {
                    value = (data_vals[cellindex] == 1) ? g_char_yes : "";
                    if (!isEmpty(this.m_fnCallBackOnClickCell)) {
                        fnOnClickCell = "event.stopPropagation();" + this.m_fnCallBackOnClickCell + "(" + rowOrderIndex + "," + cellindex + ")";
                        classCellEx += " checkeditable";
                    } else {
                        classCellEx += " check";
                    }

                } else if (this.data_struct[cellindex].type == "image") {
                    if (data_vals[cellindex] != "") {
                        var fnOnClickImage = "";
                        if (!isEmpty(this.m_fnCallBackOnClickCell)) {
                            fnOnClickImage = "event.stopPropagation();" + this.m_fnCallBackOnClickCell + "(" + rowOrderIndex + "," + cellindex + ")";
                        }
                        value = "<img src='" + data_vals[cellindex] + "' style='height:" + (g_ui_rowheight - 8) + "px' onclick='" + fnOnClickImage + "'>";
                    }
                    else {
                        if (!isEmpty(this.m_fnCallBackOnClickCell)) {
                            fnOnClickCell = "event.stopPropagation();" + this.m_fnCallBackOnClickCell + "(" + rowOrderIndex + "," + cellindex + ")";
                        }
                        value = "";
                    }

                }
                else
                    value = data_vals[cellindex];
                //value da duoc dinh dang kieu vn
                if (this.data_struct[cellindex].type == "number") {
                    value = formatNumberZS(value);
                }

                //thong tin phu
                var subinf = "";
                if (!isEmpty(this.data_struct[cellindex].subinfo) && (dsIsVisible(this.data_struct, cellindex))) {
                    var subinfoclass = "subinfo";
                    for (var n = 0; n < this.data_struct[cellindex].subinfo.length; n++) {
                        var index = this.data_struct[cellindex].subinfo[n];
                        if (!isEmpty(data_vals[index])) {
                            subinfoclass = 'subinfo';
                            if (!isEmpty(this.data_struct[j].subinfoclass)) {
                                subinfoclass = this.data_struct[j].subinfoclass;
                            }
                            if (!isEmpty(this.data_struct[index].class)) subinfoclass += (" " + this.data_struct[index].class);
                            if (!isEmpty(this.data_struct[index].subinfobreak))
                                subinf += this.data_struct[index].subinfobreak;
                            else
                                subinf += "<br>";
                            subinf += "<span class='" + subinfoclass + "'>" + escapeHTML(data_vals[index]) + "</span>";
                        }
                    }
                }

                //class style
                if (!isEmpty(this.data_struct[cellindex].class)) {
                    classCellEx += " " + this.data_struct[cellindex].class;
                }
                cell += "<div class='gridcell" + classCellEx + "' style='" + style + "' id='" + cellid + "' onclick='" + fnOnClickCell + "' >" + value + "</div>";
                //khong chinh sua - nhung yeu cau co
                if (this.data_struct[cellindex].required == 1) {
                    cell += "<input type='hidden' name='" + name + "' value='" + (data_vals[cellindex]) + "'>";
                }
            }
        }
        else {
            cell = "<input type='hidden' id='" + cellid + "' name='" + name + "' value='" + (value) + "'>";
        }
        return cell;
    }
    //subinfo se xuong dong thu 2 phia duoi, tuong voi cac cell chinh phia tren
    //chi visible = 1 moi hien thi
    showGridUpdateable_GenRow(data_vals, rowOrderIndex) {
        if (!Array.isArray(data_vals)) return "";
        var nExtraButtonCount = Array.isArray(this.m_arExtraButtons) ? this.m_arExtraButtons.length : 0;
        var prev_data_vals = (rowOrderIndex > 0) ? this.data_rows[rowOrderIndex - 1] : null;
        var id = data_vals[0];
        var idrow = this.getRowId(id);
        var idsub = this.getIdSub(data_vals);
        //xac dinh row co phai la nguyen lieu khong?
        //gia tri chua trong parent_id nam o row khac
        var bIsMaterial = false;
        if (!isEmpty(this.data_struct[0].parent)) {
            var parent_index = parseNumberVn(this.data_struct[0].parent);
            if ((parent_index > 0) && (parent_index < this.data_struct.length)) {
                if (!isEmpty(data_vals[parent_index])) bIsMaterial = true;
            }
        }
        //cells_start
        var bIsMixedRow = this.showGridUpdateable_IsMixedRow(data_vals);//row nay chua prd co materials
        var cells = "";
        var cellsubs = "";
        for (var j = 1; j < data_vals.length; j++) {
            var prevcellval = null;
            if (prev_data_vals != null) prevcellval = prev_data_vals[j];
            var cell = this.showGridUpdateable_GenCell(data_vals, id, idsub, rowOrderIndex, bIsMixedRow, j, prevcellval, nExtraButtonCount);
            if (dsIsVisible(this.data_struct, j) <= 1)
                cells += cell;
            else if (dsGetVisible(this.data_struct, j) > 1)
                cellsubs += cell;
            /*
            var cellid = this.getCellId(this.data_struct[j].name, id, idsub);
            var classCellEx = "";
            var fnOnClickCell = "";
            var value = "", name = "", style = "";
            name = this.data_struct[j].name + id;
            value = data_vals[j];

            //first pin image
            if (this.collapsible && j == this.nFirstVisibledCell && bIsMixedRow) {
                style += ";padding-left:" + g_ui_expandsignwidth + "px";
            }
            //first cell
            if (j == this.nFirstVisibledCell) {
                if (!isEmpty(this.m_fnCallBackOnClick)) {
                    classCellEx += " click";
                }
            }
            if (this.data_struct[j].type == "number") {
                style += ";text-align:right;justify-content:right;";
                value = formatNumberZS(value);
            }
            if (!isEmpty(dsGetWidth(this.data_struct, j))) {
                if (j == this.nLastVisibledCell) {
                    style += ";width:calc(" + dsGetWidth(this.data_struct, j) + " - " + (nExtraButtonCount * parseNumberVn(g_ui_cmdwidth)) + "px)";
                }
                else {

                    style += ";width:" + dsGetWidth(this.data_struct, j);
                }

            }

            //visible: cell, subinfo, second-row
            var visiblej = dsGetVisible(this.data_struct, j);
            if (visiblej == 1 || visiblej == 2) {
                var cell = "";
                var celleditable = this.data_struct[j].editable;
                if (this.m_fnCallBackCheckCellEditable != null) {
                    celleditable = this.m_fnCallBackCheckCellEditable(data_vals, j);
                }
                if (celleditable) {
                    var fOnChange = "";
                    var input_width = "100%";
                    if (this.collapsible && j == this.nFirstVisibledCell) {
                        input_width = "calc(100% - " + g_ui_expandsignwidth + "px)";
                    }
                    //vi onchange su dung '' nen fOnChange su dung "" cho cac param
                    if (!isEmpty(this.m_fnCallBackOnChange)) {
                        fOnChange = " " + this.m_fnCallBackOnChange + "(this";
                        fOnChange += ",\"" + this.data_struct[j].name + "\"";
                        for (var k = 0; k < data_vals.length; k++) {
                            fOnChange += ",\"" + escapeJS(data_vals[k]) + "\"";
                        }
                        fOnChange += ")";
                    }

                    cell += "<div class='gridcell padding0' style='" + style + "'>";

                    //luu y value: Binh` Bong' - \'8935032704621
                    if (this.data_struct[j].type == "number") {
                        cell += "<input type='text' id='" + cellid + "' onclick='event.stopPropagation(); ' class='asdivcell_input' style='text-align: right;width:" + input_width
                            + "' onchange='" + escapeHTML(fOnChange)
                            + "' onfocus='this.select()' onkeyup='return fi_doFormat(this)' name='" + name + "' value='" + (value) + "'>";
                    } else {
                        cell += "<input type='text' id='" + cellid + "' onclick='event.stopPropagation(); ' class='asdivcell_input' style='width:" + input_width
                            + "' onchange='" + escapeHTML(fOnChange)
                            + "' onfocus='this.select()' name='" + name + "' value='" + escapeHTML(value) + "'>";
                    }
                    cell += "</div>";

                }
                else {
                    if ((this.data_struct[j].merge == 1) && (prev_data_vals != null)) {
                        if (data_vals[j] == prev_data_vals[j]) {
                            value = "";
                        }
                        else {
                            value = data_vals[j];
                        }
                    }
                    else if (this.data_struct[j].type == "check") {
                        if (data_vals[j] == "")
                            value = "";
                        else
                            value = g_char_yes;

                        if (!isEmpty(this.m_fnCallBackOnClickCell)) {
                            fnOnClickCell = "event.stopPropagation();" + this.m_fnCallBackOnClickCell + "(" + rowOrderIndex + "," + j + ")";
                            classCellEx += " checkeditable";
                        } else {
                            classCellEx += " check";
                        }

                    } else if (this.data_struct[j].type == "image") {
                        if (data_vals[j].length > 0) {
                            var fnOnClickImage = "";
                            if (!isEmpty(this.m_fnCallBackOnClickCell)) {
                                fnOnClickImage = "event.stopPropagation();" + this.m_fnCallBackOnClickCell + "(" + rowOrderIndex + "," + j + ")";
                            }
                            value = "<img src='" + data_vals[j] + "' style='height:" + (g_ui_rowheight - 8) + "px' onclick='" + fnOnClickImage + "'>";
                        }

                        else
                            value = "";
                    }
                    else
                        value = data_vals[j];
                    //value da duoc dinh dang kieu vn
                    if (this.data_struct[j].type == "number") {
                        value = formatNumberZS(value);
                    }

                    //thong tin phu
                    var subinf = "";
                    if (!isEmpty(this.data_struct[j].subinfo) && (dsIsVisible(this.data_struct, j))) {
                        var subinfoclass = "subinfo";
                        for (var n = 0; n < this.data_struct[j].subinfo.length; n++) {
                            var index = this.data_struct[j].subinfo[n];
                            if (!isEmpty(data_vals[index])) {
                                subinfoclass = 'subinfo';
                                if (!isEmpty(this.data_struct[j].subinfoclass)) {
                                    subinfoclass = this.data_struct[j].subinfoclass;
                                }
                                if (!isEmpty(this.data_struct[index].class)) subinfoclass += (" " + this.data_struct[index].class);
                                if (!isEmpty(this.data_struct[index].subinfobreak))
                                    subinf += this.data_struct[index].subinfobreak;
                                else
                                    subinf += "<br>";
                                subinf += "<span class='" + subinfoclass + "'>" + escapeHTML(data_vals[index]) + "</span>";
                            }
                        }
                    }

                    //class style
                    if (!isEmpty(this.data_struct[j].class)) {
                        classCellEx += " " + this.data_struct[j].class;
                    }

                    cell += "<div class='gridcell" + classCellEx + "' style='" + style + "' id='" + cellid + "' onclick='" + fnOnClickCell + "' >" + value + "</div>";
                    //khong chinh sua - nhung yeu cau co
                    if (this.data_struct[j].required == 1) {
                        cell += "<input type='hidden' name='" + name + "' value='" + (data_vals[j]) + "'>";
                    }
                }
                
                if (dsIsVisible(this.data_struct, j))
                    cells += cell;
                else if (dsGetVisible(this.data_struct, j) > 1)
                    cellsubs += cell;
            }
            else {
                cells += "<input type='hidden' id='" + cellid + "' name='" + name + "' value='" + (value) + "'>";
            }
            */
        }

        //cells_end
        if (Array.isArray(this.m_arExtraButtons)) {
            var buttons = "";
            for (var k = 0; k < this.m_arExtraButtons.length; k++) {
                var classBt = this.m_arExtraButtons[k].class;
                if (isEmpty(classBt)) classBt = "gridcell cmd";
                buttons += "<span class=\"" + classBt + "\" style=\"float:right;width:" +
                    g_ui_cmdwidth + "px;\" onclick=\"event.stopPropagation();" +
                    this.m_arExtraButtons[k].function + "(";
                for (var pr = 0; pr < data_vals.length; pr++) {
                    buttons += "'" + escape(data_vals[pr]) + "',";
                }
                buttons += rowOrderIndex;
                buttons += ");\">" + this.m_arExtraButtons[k].caption + "</span>";
            }
            cells += buttons;
        }

        var fnOnClick = "";
        if (!isEmpty(this.m_fnCmd)) {
            fnOnClick = this.m_fnCmd + "(";
            for (var k = 0; k < data_vals.length; k++) {
                if (k > 0) fnOnClick += ",";
                fnOnClick += "\"" + escapeJS(data_vals[k]) + "\"";
            }
            fnOnClick += ")";
        }

        var row = "", classRowEx = "", stylewidthsubinfo = "";
        if (bIsMixedRow) classRowEx += " mixed";
        if (bIsMaterial) classRowEx += " material";
        if (cellsubs.length > 0) stylewidthsubinfo = "style=\"overflow-y:auto;height:auto\"";
        //hang to hop
        if (bIsMixedRow) {

            var idrowmain = this.getRowIdMainCollapsiable(id);
            var idrowsub = this.getRowIdSubCollapsiable(id);
            row = "<div class=\"list_item collapsible\" " + stylewidthsubinfo + " id=\"" + idrowmain
                + "\" onclick=\"event.stopPropagation();divToggle('" + idrowmain + "','" + idrowsub + "',"
                + escapeHTML(this.m_fnCallBackOnExpand) + "('" + idrowsub + "','" + data_vals[0] + "'))\">";
            row += cells;
            if (cellsubs.length > 0)
                row += "<div class='list_item sub'>" + cellsubs + "</div>";
            row += "<div class='list_item collapsiblecontent' id='" + idrowsub + "'></div>";
            row += "</div>";
        } else {

            row = "<div class=\"list_item" + classRowEx + "\" " + stylewidthsubinfo + " id =\"" + idrow + "\" onclick=\"event.stopPropagation();"
                + escapeHTML(fnOnClick) + ";\">";
            row += cells;
            if (cellsubs.length > 0)
                row += "<div class='list_item sub'>" + cellsubs + "</div>";
            row += "</div>";
        }
        return row;
    }

    showGridCollapsible_AddRow(data, idcontainer) {

        if (isEmpty(idcontainer)) idcontainer = this.m_idContent;
        var data_vals;
        if (Array.isArray(data))
            data_vals = data;
        else
            data_vals = data.split(g_split_val);

        var row = this.showGridCollapsible_GenRow(data_vals);
        var idrh = document.getElementById(this.getRowHeadingId());
        if (isEmpty(idrh)) return;
        if (isEmpty(idrh.parentNode)) return;
        idrh = idrh.parentNode;
        idrh.outerHTML = idrh.outerHTML + row;
    }

    //dung function divToggle
    //1 dong hien thi dang table cell, phia duoi an 1 div chua noi dung expand ra
    //fnRowCmdCB: hien thi 1 nut cuoi dong nhan goi ham fnRowCmdCB
    showGridCollapsible(data, idcontainer, fnCallBackOnExpand, arExtraButtons) {
        if (this.data_rows != null) {
            this.data_rows = [];
            this.data_rows = null;
        }
        this.viewmode = "grid";
        this.collapsible = true;
        this.m_fnCallBackOnExpand = fnCallBackOnExpand;
        this.m_idContent = idcontainer;
        if (!isEmpty(arExtraButtons)) this.m_arExtraButtons = arExtraButtons;
        if (Array.isArray(this.m_arExtraButtons)) this.nExtraButtonCount = this.m_arExtraButtons.length;

        var rowheading = "<div class='divtable'>" + this.genRowHeading() + "</div>";
        if (data.length < 1) {
            var idshow = document.getElementById(idcontainer);

            if (!isEmpty(idshow)) {

                idshow.innerHTML = rowheading;
            } else {
                return rowheading;
            }
            return;
        }
        var rows = data.split(g_split_row);
        var row_count = rows.length;
        var allrows = "", j = 0, i = 0, pageno = 0, pagecount = 0, pagesize = 20, startindex = 0;
        if (rows[0].substr(0, g_sign_pageconfig.length) == g_sign_pageconfig) {
            var configs = rows[0].split(g_split_val);
            startindex = 1;
            if (configs.length == 3) {
                pagesize = parseInt(configs[0]);
                pageno = parseInt(configs[1]);
                pagecount = parseInt(configs[2]);
            }
        }
        this.data_rows = [];
        for (i = startindex; i < row_count; i++) {
            var data_vals = rows[i].split(g_split_val);
            var row = this.showGridCollapsible_GenRow(data_vals);
            this.data_rows[this.data_rows.length] = Array.from(data_vals);
            allrows += row;
        }

        var pageinfo = DlgSelect.getPageIndexSelect(pageno, pagecount, "showList");
        var html = rowheading + allrows + pageinfo;

        if (!isEmpty(idcontainer)) {
            setInnerById(idcontainer, html);
        } else {
            return html;
        }

    }
    findRowheadingInTable(iddivtable) {
        if (iddivtable === undefined) return null;
        if (iddivtable == null) return null;
        var searchEles;
        if (isString(iddivtable)) {
            searchEles = document.getElementById(iddivtable);
            if (searchEles === null) return null;
            searchEles = searchEles.children;
        }
        else
            searchEles = iddivtable.children;

        if (searchEles === undefined) return; if (searchEles === null) return; if (searchEles.length < 1) return;
        if (searchEles[0].classList == "divtable")
            searchEles = searchEles[0].children;
        if (searchEles === undefined) return; if (searchEles === null) return; if (searchEles.length < 1) return;
        if (searchEles.length < 1) return;
        for (var i = 0; i < searchEles.length; i++) {

            if (searchEles[i].classList == "divrow heading") {
                return searchEles[i];
            }
        }
    }

    showGrid_UpdateCell(divnamecontainer, columnname, idvalincell, newvalue) {
        var idvalincell = this.getCellId(columnname, idvalincell);
        setInnerById(idvalincell, newvalue);

        var searchEles = null;
        if (isString(divnamecontainer))
            searchEles = document.getElementById(divnamecontainer).children;
        else
            searchEles = divnamecontainer.children;
        if (searchEles === undefined) return; if (searchEles === null) return; if (searchEles.length < 1) return;
        if (searchEles[0].classList == "divtable")
            searchEles = searchEles[0].children;
        if (searchEles === undefined) return; if (searchEles === null) return; if (searchEles.length < 1) return;
        if (searchEles.length < 1) return;
        for (var i = 0; i < searchEles.length; i++) {
            if (searchEles[i].classList == "divrow") {
                var cols = searchEles[i].children;
                if (cols === undefined) continue; if (cols === null) continue; if (cols.length < 1) continue;
                for (var j = 0; j < cols.length; j++) {
                    if (cols[j].id.indexOf(columnname) == 0) {
                        if (cols[j].id == idvalincell) {
                            cols[j].innerHTML = newvalue;
                            break;
                        }
                    }
                }
            }
        }

    }

    //cau truc table: divtable->divrow->cell (columname+idval)
    viewSetOneChecked(divnamecontainer, columnname, idvalchecked, checkvalue = 1, clearothercheck = 1) {
        var idcellchecked = this.getCellId(columnname, idvalchecked);
        var searchEles = null;

        if (isString(divnamecontainer))
            searchEles = document.getElementById(divnamecontainer).children;
        else
            searchEles = divnamecontainer.children;
        if (searchEles === undefined) return; if (searchEles === null) return; if (searchEles.length < 1) return;
        if (searchEles[0].classList == "divtable")
            searchEles = searchEles[0].children;
        if (searchEles === undefined) return; if (searchEles === null) return; if (searchEles.length < 1) return;
        if (searchEles.length < 1) return;
        for (var i = 0; i < searchEles.length; i++) {

            if (searchEles[i].classList == "divrow") {
                var cols = searchEles[i].children;
                if (cols === undefined) continue; if (cols === null) continue; if (cols.length < 1) continue;
                for (var j = 0; j < cols.length; j++) {
                    if (cols[j].id.indexOf(columnname) == 0) {
                        if (cols[j].id == idcellchecked) {
                            if (checkvalue === 1)
                                cols[j].innerHTML = "&#10003";
                            else
                                cols[j].innerHTML = "";
                        }
                        else if (clearothercheck === 1)
                            cols[j].innerHTML = "";
                    }
                }
            }
        }

    }
    //data co the gom nhieu row - vi du nhu truong hop merge
    //isSubRow: neu true se khong hien thi cac cell merge=1
    showGrid_UpdateRow(data, bIsSubRow, idRowReplace) {
        var row_html = "";
        var iditem = null;
        var idrow = null;
        var data_vals;
        if (Array.isArray(data))
            data_vals = data;
        else
            data_vals = data.split(g_split_val);
        if (data_vals.length <= 0) {
            showMsg(itxt("khongcodulieu"));
            return false;
        }

        var id = data_vals[0];
        var idsub = this.getIdSub(data_vals);
        if (!isEmpty(idRowReplace))
            idrow = idRowReplace;
        else
            idrow = this.getRowId(id, idsub);
        alert(idrow + ":" + id);
        iditem = document.getElementById(idrow);

        var prev_data_vals = null;
        if (bIsSubRow) prev_data_vals = data_vals;
        row_html = this.showGrid_GenRow(data_vals, null, prev_data_vals);
        //khong con iditem khi la subrow
        if (!isEmpty(iditem))
            iditem.outerHTML = row_html;
        else {
            var parent = document.getElementById(this.getRowId(id));
            if (!isEmpty(parent)) parent.outerHTML = parent.outerHTML + row_html;
        }
        return true;
    }

    //visible=0,1,2
    //data la 1 chuoi dinh dang hoac la 1 array cua obj
    //neu idContent=null tra ve noi dung html
    //fnViewOtherPage (pageno,params)
    showGrid(data, idContent, fnCmd, fnCmdTitle, fnCmdParams, idRowPrefix, fnViewOtherPage, fnViewOtherPageParams) {
        if (this.data_rows != null) {
            this.data_rows = [];
            this.data_rows = null;
        }
        this.m_idContent = idContent;
        this.m_fnCmd = fnCmd;
        this.m_fnCmdTitle = fnCmdTitle;
        this.m_fnCmdParams = fnCmdParams;
        this.viewmode = "grid";
        this.collapsible = false;
        if (Array.isArray(this.m_arExtraButtons)) this.nExtraButtonCount = this.m_arExtraButtons.length;

        if (this.m_fnCmdTitle === undefined) this.m_fnCmdTitle = "&#9783";
        if (isEmpty(fnViewOtherPage)) fnViewOtherPage = "showList";
        if (isEmpty(fnViewOtherPageParams)) fnViewOtherPageParams = "";
        var idshow = null;
        if (isString(idContent)) {
            idshow = document.getElementById(idContent);
        }
        else
            idshow = idContent;
        var retHtml = "";

        //ROW_HEADING
        var rowheading = this.genRowHeading();

        if (data.length < 1) {
            retHtml = "<div class='divtable'>" + rowheading + "</div>";
            if (!isEmpty(idshow))
                idshow.innerHTML = retHtml;
            else
                return retHtml;
            return;
        }

        //ROW_LIST
        var rows = null;
        if (Array.isArray(data))
            rows = data;
        else
            rows = data.split(g_split_row);

        var row_count = rows.length;

        if (row_count < 1) {
            retHtml = "<div class='divtable'>" + rowheading + "</div>";
            if (!isEmpty(idshow))
                idshow.innerHTML = retHtml;
            else
                return retHtml;
            return;
        }

        var allrows = "", j = 0, i = 0, pageno = 0, pagecount = 0, pagesize = 20, startindex = 0;
        if (typeof rows[0] != "object") {
            if (rows[0].substr(0, g_sign_pageconfig.length) == g_sign_pageconfig) {
                var configs = rows[0].split(g_split_val);
                startindex = 1;
                if (configs.length == 3) {
                    pagesize = parseInt(configs[0]);
                    pageno = parseInt(configs[1]);
                    pagecount = parseInt(configs[2]);
                }
            }
        }
        var prev_data_vals = null;
        this.data_rows = [];
        for (i = startindex; i < row_count; i++) {
            var data_vals;
            if (typeof rows[i] == "object") {
                data_vals = Array();
                for (var k = 0; k < this.data_struct.length; k++) {
                    var valname = this.data_struct[k].name;
                    data_vals[k] = rows[i][valname];
                }
            }
            else {
                data_vals = rows[i].split(g_split_val);
            }
            var row = this.showGrid_GenRow(data_vals, false, prev_data_vals);
            this.data_rows[this.data_rows.length] = Array.from(data_vals);
            allrows += row;
            prev_data_vals = data_vals;
        }


        var pageinfo = DlgSelect.getPageIndexSelect(pageno, pagecount, fnViewOtherPage, fnViewOtherPageParams);
        if (!isEmpty(idshow))
            idshow.innerHTML = "<div class='divtable'>" + rowheading + allrows + "</div>" + pageinfo;
        else
            return "<div class='divtable'>" + rowheading + allrows + "</div>" + pageinfo;
    }

    showGrid_AddRow(data) {
        var data_vals;
        if (Array.isArray(data))
            data_vals = data;
        else
            data_vals = data.split(g_split_val);
        var row = this.showGrid_GenRow(data_vals);
        var idrh = this.findRowheadingInTable(this.m_idContent);
        if (isEmpty(idrh))
            idrh == document.getElementById(this.getRowHeadingId());
        if (!isEmpty(idrh)) {
            idrh.outerHTML = idrh.outerHTML + row;
        }
    }
    //phan tu dau mac dinh la id
    //bKeepSelectValToDisplay=true: gia tri la gia tri hien thi, khong tim trong danh sach data (ket qua edit/add)
    showGrid_GenRow(data_vals, bKeepSelectValToDisplay, prev_data_vals) {
        var cmd = "", row = "";
        var idparam = "";
        var j = 0;
        var id = data_vals[0];
        var idsub = this.getIdSub(data_vals);
        var idrow = this.getRowId(id, idsub);
        var fnonclick = "";
        //cmd
        if (!isEmpty(this.m_fnCmd)) {
            if (this.data_struct[0].type == "text")
                idparam = "\"" + data_vals[0] + "\"";
            else
                idparam = data_vals[0];
            if (idparam != "") {

                fnonclick = this.m_fnCmd + "(" + idparam;

                if (!isEmpty(idsub))
                    fnonclick += "," + idsub;
                if (this.m_fnCmdParams != null) {
                    if (Array.isArray(this.m_fnCmdParams)) {
                        var arparams = "";
                        for (j = 0; j < this.m_fnCmdParams.length; j++) {
                            if (arparams != "") arparams += ",";
                            arparams += "\"" + escapeJS(this.m_fnCmdParams[j].toString()) + "\"";
                        }
                        fnonclick += ",[" + arparams + "]";
                    }
                    else {
                        fnonclick += ",\"" + this.m_fnCmdParams.toString() + "\"";
                    }
                }
                fnonclick += ")";

                var classButton = "buttonincell";
                if (this.m_fnCmdTitle == g_char_x) classButton += " remove";
                cmd = "<input type='button' class='" + classButton + "' value='" + this.m_fnCmdTitle + "' onclick='" + escapeHTML(fnonclick) + "'>";
            }
        }
        var classRowEx = "";
        if (this.bItemMultiRow) classRowEx = " multiline";
        var cc = data_vals.length;

        if ((this.data_struct[cc - 1].name == "highlight") && (this.data_struct[cc - 1].type == "highlight")) {
            if (data_vals[cc - 1] == 0) classRowEx = " highlight";
        }
        row = "<div class='divrow" + classRowEx + "' id='" + idrow + "' onclick='event.stopPropagation();" + escapeHTML(fnonclick) + "'>";
        for (j = 1; j < data_vals.length; j++) {
            if (isEmpty(this.data_struct[j].rowsub)) {
                row += this.showGrid_GenRowCell(j, (j == this.nFirstVisibledCell), data_vals, prev_data_vals, bKeepSelectValToDisplay);
            }
        }

        //buttons
        if (Array.isArray(this.m_arExtraButtons)) {
            var buttons = "";
            for (var k = 0; k < this.m_arExtraButtons.length; k++) {
                var classBt = this.m_arExtraButtons[k].class;
                if (isEmpty(classBt)) classBt = "gridcell cmd";

                //border-right of cell
                buttons += "<div class='" + classBt + "' style='width:" + (g_ui_cmdwidth - 1) + "px;' onclick=\"event.stopPropagation();" + this.m_arExtraButtons[k].function + "('" + data_vals[0] + "');\">" + this.m_arExtraButtons[k].caption + "</div>";
            }
            row += "<div class='divcell' style='padding:0px;text-align:center;'>" + buttons + "</div>";

        }

        if (this.bItemMultiRow) {
            var rowsub = this.genRow_Sub(data_vals);;
            if (rowsub.length > 0) {
                row += rowsub;
            }
        }
        row += "</div>";

        return row;
    }
    showGrid_GenRowCell(j, bIsFirstVisibleCell, data_vals, prev_data_vals, bKeepSelectValToDisplay, cellClass) {
        if (isEmpty(cellClass)) cellClass = "divcell";
        var idsub = this.getIdSub(data_vals);
        var cellid = this.getCellId(this.data_struct[j].name, data_vals[0], idsub);
        var row = "";
        var cell_merge = false;
        var value = data_vals[j];
        var style = "";
        if (this.data_struct[j].type == "number") {
            style = "text-align:right;";
            if (this.data_struct[j].round == 1) {
                value = roundNumber(value);
            }
            value = formatNumberZS(value);
        }

        if (dsIsVisible(this.data_struct, j)) {
            if (!isEmpty(this.data_struct[j].fordisplay)) {
                value = data_vals[j];
                for (var fd = 0; fd < this.data_struct[j].fordisplay.length; fd++) {
                    if (this.data_struct[j].fordisplay[fd].id == value) {
                        value = this.data_struct[j].fordisplay[fd].name;
                        break;
                    }
                }
            } else if (this.data_struct[j].merge == 1) {
                if (!isEmpty(prev_data_vals)) {
                    if ((data_vals[j] === prev_data_vals[j]) && (!isEmpty(data_vals[j]))) {
                        cell_merge = true;
                        value = "";
                    }
                    else
                        value = data_vals[j];

                } else {
                    value = data_vals[j];
                }
            }
            else if (this.data_struct[j].type == "check") {
                if ((data_vals[j] == "") || (data_vals[j] == "0"))
                    value = "";
                else {
                    value = g_char_yes;
                    style = "text-align:center;";
                }
            } else if (this.data_struct[j].type == "select") {
                if (bKeepSelectValToDisplay) {
                    value = data_vals[j];
                } else {
                    var sdata;
                    if (isString(this.data_struct[j].data))
                        sdata = eval(this.data_struct[j].data);
                    else
                        sdata = this.data_struct[j].data;

                    var selectIndex = -1;
                    if (data_vals[j] != "")
                        selectIndex = parseNumberVn(data_vals[j]);
                    if (!Array.isArray(sdata)) {
                        value = "err:not array";
                    } else if ((selectIndex >= 0) && (selectIndex < sdata.length)) {
                        if (isObject(sdata[selectIndex]))
                            value = sdata[selectIndex].name;
                        else
                            value = sdata[selectIndex];
                    } else {
                        value = "";
                    }
                }
            }

            //thong tin phu
            if (!isEmpty(this.data_struct[j].subinfo) && !cell_merge) {
                var subinfo = "", sclass = "", svalue = "";
                for (var n = 0; n < this.data_struct[j].subinfo.length; n++) {
                    sclass = "";
                    var subindex = this.data_struct[j].subinfo[n];
                    if (isEmpty(this.data_struct[subindex].subinfobreak))
                        subinfo += "<br>";
                    else
                        subinfo += this.data_struct[subindex].subinfobreak;
                    svalue = data_vals[subindex];
                    if (this.data_struct[subindex].type == "number") svalue = formatNumberZS(svalue);
                    if (!isEmpty(this.data_struct[subindex].subinfoclass)) sclass = this.data_struct[subindex].subinfoclass;
                    if (!isEmpty(this.data_struct[subindex].class)) sclass = this.data_struct[subindex].class;
                    var scellid = this.getCellId(this.data_struct[subindex].name, data_vals[0], idsub);
                    subinfo += "<span id='" + scellid + "' class='" + sclass + "'>" + svalue + "</span>";
                }

                if (!isEmpty(this.data_struct[j].maininfoclass))
                    value = "<span class='" + this.data_struct[j].maininfoclass + "'>" + value + "</span>";
                if (!isEmpty(this.data_struct[j].subinfoclass))
                    value += "<span class='" + this.data_struct[j].subinfoclass + "'>" + subinfo + "</span>";
                else
                    value += subinfo;
            }

            if (bIsFirstVisibleCell) {
                //first pin image
                if (this.collapsible) style += ";padding-left:16px;";
                if (!isEmpty(this.m_fnCmd) && !cell_merge) {
                    cellClass = cellClass + " click";
                }
            }
            if (!isEmpty(this.data_struct[j].class)) cellClass += " " + this.data_struct[j].class;
            if (cell_merge) style += ";border-top:0px;";

            if (j == this.nLastVisibledCell) {
                style += "width:calc(" + dsGetWidth(this.data_struct, j) + " - " + (this.nExtraButtonCount * parseNumber(g_ui_cmdwidth)) + "px);";

            }

            else
                style += "width:" + dsGetWidth(this.data_struct, j) + ";";

            //gen cell
            if (this.bItemMultiRow) {
                row += "<div class='divcellmultirowup' style='" + style + "' id='" + cellid + "'>" + (value) + "</div>";
            } else {
                row += "<div class='" + cellClass + "' style='" + style + "' id='" + cellid + "'>" + (value) + "</div>";
            }
        }
        else {
            row += "<input type='hidden' id='" + cellid + "' value='" + (value) + "'>";
        }
        return row;

    }

    //su dung table,khong dung div
    showGridEx(data, idcontainer, fnCallBack, fnCallBackParams, fnViewOtherPage, fnViewOtherPageParams) {
        if (this.data_rows != null) {
            this.data_rows = [];
            this.data_rows = null;
        }
        this.viewmode = "gridex";
        this.collapsible = true;
        this.m_fnCmd = fnCallBack;
        this.m_fnCmdParams = fnCallBackParams;
        this.m_idContent = idcontainer;
        if (Array.isArray(this.m_arExtraButtons)) this.nExtraButtonCount = this.m_arExtraButtons.length;
        var rows = data.split(g_split_row);
        var row_count = rows.length;
        if (row_count < 1)
            return;


        var allrows = "", j = 0, i = 0, pageno = 0, pagecount = 0, pagesize = 20, startindex = 0;

        if (rows[0].substr(0, g_sign_pageconfig.length) == g_sign_pageconfig) {
            var configs = rows[0].split(g_split_val);
            startindex = 1;

            if (configs.length == 3) {
                pagesize = parseInt(configs[0]);
                pageno = parseInt(configs[1]);
                pagecount = parseInt(configs[2]);
            }
        }
        var prev_data_vals = null;
        var rsMap = new Map();
        this.data_rows = [];
        for (i = startindex; i < row_count; i++) {
            var data_vals = rows[i].split(g_split_val);
            var idrowmain = this.getRowIdMainCollapsiable(data_vals[0]);
            var idrowsub = this.getRowIdSubCollapsiable(data_vals[0]);
            var idsub = this.getIdSub(data_vals);
            var val_display = "";
            //ITEM_START
            //var row = "<tr id=\"" + idrowmain + "\" onclick=\"divToggle('" + idrowmain + "','" + idrowsub + "','" + fnCallBack + "',[" + data_vals[0] + ",'" + idrowsub + "'])\">";
            var fn = fnCallBack + "('" + data_vals[0] + "'";
            if ((Array.isArray(fnCallBackParams)) && (fnCallBackParams.length > 0)) {
                fn += "," + arrayToStringAsList(fnCallBackParams);
            }
            fn += ")";
            var row = "<tr id=\"" + idrowmain + "\" onclick=\"" + fn + "\">";
            //cells
            for (j = 1; j < data_vals.length; j++) {
                var cellid = this.getCellId(this.data_struct[j].name, data_vals[0], idsub);
                if (dsIsVisible(this.data_struct, j)) {
                    var style = "";
                    if (this.data_struct[j].type == "number") style += ";text-align:right";
                    if (!isEmpty(dsGetWidth(this.data_struct, j))) style += ";width:" + dsGetWidth(this.data_struct, j);
                    if (j == 1) {
                        style += ";padding-left:16px";
                    }
                    val_display = data_vals[j];
                    if (this.data_struct[j].type == "number") val_display = formatNumberZS(val_display);;
                    if (!isEmpty(this.data_struct[j].subinfo)) {
                        val_display += this.getSubInfoValue(data_vals, j);
                    }
                    if (this.data_struct[j].merge == 1) {
                        if (prev_data_vals != null) {
                            if (data_vals[j] == prev_data_vals[j]) {
                                var val = parseNumberVn(rsMap.get(this.data_struct[j].name)) + 1;
                                rsMap.set(this.data_struct[j].name, val);
                                //hang cuoi cung
                                if (i == (row_count - 1)) {
                                    allrows = allrows.replaceAll('{_' + this.data_struct[j].name + 'ROWSPAN_}', rsMap.get(this.data_struct[j].name));
                                }
                                continue;
                            } else {
                                //prev_data_vals = null;
                                allrows = allrows.replaceAll('{_' + this.data_struct[j].name + 'ROWSPAN_}', rsMap.get(this.data_struct[j].name));
                            }
                        }
                        rsMap.set(this.data_struct[j].name, 1);
                        row += "<td rowspan='{_" + this.data_struct[j].name + "ROWSPAN_}' style='" + style + "' id='" + cellid + "'>" + val_display + "</td>";
                    } else {
                        row += "<td style='" + style + "' id='" + cellid + "'>" + val_display + "</td>";
                    }
                }
                else {
                    //row += "<td style='width:0px' id='" + cellid + "'>" + data_vals[j] + "</td>";
                    row += "<input type='hidden' id='" + cellid + "' value='" + data_vals[j] + "'>";
                }
            }
            //row-expand
            //row += "<div class='collapsiblecontent' id='" + idrowsub + "'></div>";
            row += "</tr>";
            //ITEM_END
            allrows += row;
            prev_data_vals = data_vals;
            this.data_rows[this.data_rows.length] = Array.from(data_vals);
        }
        var rowheading = this.genRowHeading();
        var pageinfo = DlgSelect.getPageIndexSelect(pageno, pagecount, "showList");
        var html = "<table class='alter' width='100%' cellpadding='4' style='border-collapse:collapse' border='0'>" + rowheading + allrows + "</table>" + pageinfo;

        var idshow = document.getElementById(idcontainer);
        if (!isEmpty(idshow)) {
            idshow.innerHTML = html;
        } else {
            return html;
        }

    }
    showListCollapsible_AddRow(data, idcontainer, fnCmd) {
        var data_vals = data.split(g_split_val);
        var id = data_vals[0], idrow = "", cmd = "", row = "";
        var j = 0;

        idrow = this.getRowId(data_vals[0]);
        row += "<div class='collapsibleheader sub' style='margin-bottom:1px' id='" + idrow + "' onclick=\"divToggleNext(this," + fnCmd + "(" + data_vals[0] + ",'" + idrow + "sub'),0)\">";
        for (j = 1; j < data_vals.length; j++) {
            if (dsIsVisible(this.data_struct, j)) {

                row += "<span>" + data_vals[j] + "</span>";
            }
            else {
                row += "<input type='hidden' id='" + this.getCellId(this.data_struct[j].name, data_vals[0]) + "' value='" + data_vals[j] + "'>";
            }
        }
        row += "</div>";
        row += "<div class='collapsiblecontent' id='" + idrow + "sub'></div>";
        if (isString(idcontainer)) {
            var idcontainer = document.getElementById(idcontainer);
            idcontainer.innerHTML = row + idcontainer.innerHTML;
        }
        else
            idcontainer.innerHTML = row + idcontainer.innerHTML;
    }
    showList(data, idcontainer, fnCmd, fnCmdTitle, arExtraButtons) {
        if (this.data_rows != null) {
            this.data_rows = [];
            this.data_rows = null;
        }

        this.viewmode = "list";
        if (!isEmpty(fnCmd)) this.m_fnCmd = fnCmd;
        if (!isEmpty(fnCmdTitle)) this.m_fnCmdTitle = fnCmdTitle;
        if (!isEmpty(arExtraButtons)) this.m_arExtraButtons = arExtraButtons;
        this.m_idContent = idcontainer;
        if (Array.isArray(this.m_arExtraButtons)) this.nExtraButtonCount = this.m_arExtraButtons.length;
        if (!isEmpty(idcontainer)) {
            this.idcontainer = idcontainer;
        } else {
            if (isEmpty(idcontainer)) idcontainer = this.idcontainer;
        }
        if (isEmpty(idcontainer)) {
            alert("showList: id container not specified");
            return;
        }
        var caption = this.genRowHeading();

        if (data.length < 1) {
            setInnerById(idcontainer, caption);
            return;
        }

        var rows;
        if (Array.isArray(data))
            rows = data;
        else
            rows = data.split(g_split_row);
        var row_count = rows.length;
        if (row_count < 1) {
            return;
        }

        var allrows = "", j = 0, i = 0, pageno = 0, pagecount = 0, pagesize = 20, startindex = 0;
        if (!Array.isArray(rows[0])) {
            if (rows[0].substr(0, g_sign_pageconfig.length) == g_sign_pageconfig) {
                var configs = rows[0].split(g_split_val);
                startindex = 1;

                if (configs.length == 3) {

                    pagesize = parseInt(configs[0]);
                    pageno = parseInt(configs[1]);
                    pagecount = parseInt(configs[2]);
                }
            }
        }

        this.data_rows = [];
        for (i = startindex; i < row_count; i++) {
            var data_vals;
            if (Array.isArray(rows[i]))
                data_vals = rows[i]
            else
                data_vals = rows[i].split(g_split_val);

            var id = "", idrow = "", cmd = "";
            id = data_vals[0];
            idrow = this.getRowId(data_vals[0]);
            allrows += "<div class='list_item' style='overflow:auto;padding:4px 0px;border:0px;' id='" + idrow + "'";
            if (!isEmpty(this.m_fnCmd)) {
                allrows += " onclick='event.stopPropagation();" + this.m_fnCmd + "(" + id + ");'";
            } else {
                allrows += " onclick='event.stopPropagation();'";
            }
            allrows += ">";
            var label = "";
            for (j = 1; j < data_vals.length; j++) {
                if (dsIsVisible(this.data_struct, j)) {
                    if (label != "") {
                        label += "<br>&nbsp;";
                        label += "<span>" + this.data_struct[j].head + ": <span id='" + this.getCellId(this.data_struct[j].name, data_vals[0]) + "'>" + data_vals[j] + "</span></span>";
                    }
                    else {
                        label += "<b><span id='" + this.getCellId(this.data_struct[j].name, data_vals[0]) + "'>" + data_vals[j] + "</span></b>";
                    }
                }
                else {
                    allrows += "<input type='hidden' id='" + this.getCellId(this.data_struct[j].name, data_vals[0]) + "' value='" + data_vals[j] + "'>";
                }
            }
            var buttons = "";
            if (Array.isArray(this.m_arExtraButtons)) {
                var buttons = "";
                for (var k = 0; k < this.m_arExtraButtons.length; k++) {
                    var classBt = this.m_arExtraButtons[k].class;
                    if (isEmpty(classBt)) classBt = "gridcell cmd";
                    buttons += "<span class='" + classBt + "' style='float:right;top:4px;background:cyan;color:black;position:relative;margin-bottom:8px;width:" + g_ui_cmdwidth + "px;' onclick=\"event.stopPropagation();" + this.m_arExtraButtons[k].function + "('" + data_vals[0] + "');\">" + this.m_arExtraButtons[k].caption + "</span>";
                }
            }

            allrows += "<div style='width:calc(100% - 64px);float:left;height:auto;padding-left:4px;'>" + label + "</div>";
            allrows += "<div style='width:60px;float:left;height:auto;'>" + buttons + "</div>";
            allrows += "</div>";
            this.data_rows[this.data_rows.length] = Array.from(data_vals);
        }
        allrows = "<div class='list_item_content'>" + allrows + "</div>";

        var pageinfo = "";
        if (pagecount > 1) {
            pageinfo += "<div class='pageindex'>";
            for (i = 1; i <= pagecount; i++) {
                if (i == pageno)
                    pageinfo += "<a class=\"pageindexfocus\" href=\"javascript:void(0)\" onclick=\"javascript:showList(" + i + ")\">" + i + "</a>";
                else
                    pageinfo += "<a class=\"pageindex\" href=\"javascript:void(0)\" onclick=\"javascript:showList(" + i + ")\">" + i + "</a>";
            }
            pageinfo += "</div>";

        }
        var idshow = document.getElementById(idcontainer);
        idshow.innerHTML = caption + allrows + pageinfo;
    }
    //arExtraButtons [{caption,functioncallback(id)}]
    //fnCmd: show expand details id-iddiv
    showListCollapsible(data, idcontainer, fnCmd, arExtraButtons) {
        if (this.data_rows != null) {
            this.data_rows = [];
            this.data_rows = null;
        }
        this.viewmode = "list";
        this.collapsible = true;
        this.m_arExtraButtons = arExtraButtons;
        this.m_fnCmd = fnCmd;
        this.m_idContent = idcontainer;
        if (Array.isArray(this.m_arExtraButtons)) this.nExtraButtonCount = this.m_arExtraButtons.length;
        if (data.length < 1) {
            setInnerById(idcontainer, "");
            return;
        }

        var rows = data.split(g_split_row);
        var row_count = rows.length;
        if (row_count < 1)
            return;
        var allrows = "", j = 0, i = 0, pageno = 0, pagecount = 0, pagesize = 20, startindex = 0;
        //if(fnCmd===undefined)fnCmd="menuPopupItem";
        if (rows[0].substr(0, g_sign_pageconfig.length) == g_sign_pageconfig) {
            var configs = rows[0].split(g_split_val);
            startindex = 1;

            if (configs.length == 3) {

                pagesize = parseInt(configs[0]);
                pageno = parseInt(configs[1]);
                pagecount = parseInt(configs[2]);
            }
        }
        this.data_rows = [];
        for (i = startindex; i < row_count; i++) {
            var data_vals = rows[i].split(g_split_val);
            var id = "", idrow = "", cmd = "";
            id = data_vals[0];
            idrow = this.getRowId(data_vals[0]);
            allrows += "<div class='collapsibleheader sub' style='margin-bottom:1px;' id='" + idrow + "' onclick=\"divToggleNext(this," + fnCmd + "(" + data_vals[0] + ",'" + idrow + "sub'),0)\">";
            if (Array.isArray(arExtraButtons)) {
                for (var k = 0; k < arExtraButtons.length; k++) {
                    allrows += "<input type='button' class='collapsibleheaderbutton' style='float:right' value='" + arExtraButtons[k].caption + "' onclick=\"" + arExtraButtons[k].function + "(" + data_vals[0] + ");event.stopPropagation()\">";
                }
            }
            var label = "";
            for (j = 1; j < data_vals.length; j++) {
                var cellid = this.getCellId(this.data_struct[j].name, data_vals[0]);
                if (dsIsVisible(this.data_struct, j)) {
                    if (label != "") {
                        label += "<br>&nbsp;";
                        label += "<span>" + this.data_struct[j].head + ": <span id='" + cellid + "'>" + data_vals[j] + "</span></span>";
                    }
                    else {
                        label += "<b><span id='" + cellid + "'>" + data_vals[j] + "</span></b>";
                    }
                }
                else {
                    allrows += "<input type='hidden' id='" + cellid + "' value='" + data_vals[j] + "'>";
                }
            }
            this.data_rows[this.data_rows.length] = Array.from(data_vals);
            allrows += label;
            allrows += "</div>";
            allrows += "<div class='collapsiblecontent' id='" + idrow + "sub'></div>";
        }

        var rowheading = "";
        var pageinfo = "";
        if (pagecount > 1) {
            pageinfo += "<div class='pageindex'>";
            for (i = 1; i <= pagecount; i++) {
                if (i == pageno)
                    pageinfo += "<a class=\"pageindexfocus\" href=\"javascript:void(0)\" onclick=\"javascript:showList(" + i + ")\">" + i + "</a>";
                else
                    pageinfo += "<a class=\"pageindex\" href=\"javascript:void(0)\" onclick=\"javascript:showList(" + i + ")\">" + i + "</a>";
            }
            pageinfo += "</div>";

        }
        var idshow = document.getElementById(idcontainer);
        idshow.innerHTML = "<div class='divtable'>" + rowheading + "</div>" + allrows + pageinfo;
    }
}
//END_CLASS_GRID_VIEW_EX

//*START_CLASS_GRID_VIEW

//END_CLASS_GRID_VIEW
//*START_CLASS_CONTROL
class UiControl {
    static selectInput_GetId(idcontainer) {
        return idcontainer + "input";
    }
    static inputTextSetValue(idcontainer, strvalue, idval, val) {
        var inputid = idcontainer + "input";
        setValById(inputid, "");
        UiControl.inputWithClearButtonOnInput(inputid);
        setValById(inputid, strvalue);
        if (!isEmpty(idval))
            setValById(idval, val);

        UiControl.inputWithClearButtonOnInput(inputid);
    }
    static selectInput_Update(idcontainer, idval, val_display, val_value) {
        setValById(idcontainer + "input", val_display);
        setValById(idval, val_value);
    }

    //ds_contact_c
    static selectInputContactOnSelect(fnCallBackName, idinput, idval, contact_id, contact_name, contact_phone, contact_address) {
        //khong_chon
        if (isEmpty(contact_id)) {
            contact_id = 0;
            contact_name = "";
            contact_phone = "";
            contact_address = "";
        }
        var fname = contact_name;
        if (contact_phone.length > 0)
            fname += " [" + contact_phone + "]";
        if (contact_address.length > 0)
            fname += " (" + contact_address + ")";

        setValById(idinput, fname);
        setValById(idval, contact_id);
        if (!isEmpty(fnCallBackName)) {
            var fn = fnCallBackName + "(" + arrayToStringAsList([contact_id, contact_name, contact_phone, contact_address]) + ")";
            eval(fn);
        }
    }
    //su dung datalist, hien thi tuy loai trinh duyet
    static selectInputContact(idcontainer, idval, strplaceholder, fnCallBackName) {
        if (isEmpty(fnCallBackName)) fnCallBackName = "";
        var idinput = idcontainer + "input";
        var idimagestatus = idcontainer + "imagestatus";
        var iddatalist = idcontainer + "datalist";
        var img = "imgs/customers.png";
        var strout = '<input autoComplete="off" placeholder="' + strplaceholder + '" id="' + idinput + '"' +
            ' class="inputex_inputex" type="text" style="padding-right: 26px;"' +
            ' oninput="showWaitStatus(0,\'' + idimagestatus + '\',\'' + img + '\');UiControl.getContactDataList(\'' + idinput + '\',\'' + iddatalist + '\',\'' + idval + '\');" ' +
            ' list="' + iddatalist + '"' +
            '     onchange="this.selectionStart = this.selectionEnd =0;">' +
            '   <span id="' + idimagestatus + '" class="inputex_imagestatus"></span>' +
            '   <div class="inputex_autohidegroup" style="right: 26px;">' +
            '         <button class="inputex_autohidebutton" type="button">×</button>' +
            '   </div>' +
            '   <button class="inputex_button" type="button" ' +
            '   onclick="DlgSelect.showContact(0,' +
            '\'UiControl.selectInputContactOnSelect\',[\'' + fnCallBackName + '\',\'' + idinput + '\',\'' + idval + '\']);return false;">::</button>  ' +
            ' </div>' +
            ' <datalist id="' + iddatalist + '">' +
            '     <option data-value="0">' + strplaceholder + '</option>' +
            ' </datalist>' +
            ' <input type="hidden" id="' + idval + '" name="' + idval + '">';

        setInnerById(idcontainer, strout);
        setBackgroundImageById(idimagestatus, img);
    }
    static inputTextEnterEvent(idcontainer, idinput, strPlaceholder, fnOnInputCallBack) {
        if (isEmpty(strPlaceholder)) strPlaceholder = "";
        //var strout='<div class="inputex" style="width: 100%;">' +
        var strout = '<input placeholder="' + strPlaceholder + '" name="' + idinput + '" id="' + idinput + '"' +
            ' class="inputex_input" type="text" style="padding-right: 24px;"' +
            ' onkeypress="' + fnOnInputCallBack + '(event);" ' +
            ' onchange="">' +

            '<div class="inputex_autohidegroup" style="right:1px"> ' +
            '<button class="inputex_autohidebutton" type="button">×</button>' +
            '</div>';
        setInnerById(idcontainer, strout);
    }
    static inputText(idcontainer, idinput, strPlaceholder, fnOnInputCallBack) {
        if (isEmpty(strPlaceholder)) strPlaceholder = "(nhập)";
        var strout = '<input placeholder="' + strPlaceholder + '" name="' + idinput + '" id="' + idinput + '"' +
            ' class="inputex_input" type="text" style="padding-right: 24px;"' +
            ' oninput="' + fnOnInputCallBack + '();" ' +
            ' onchange="this.selectionStart = this.selectionEnd =0;">' +

            '<div class="inputex_autohidegroup" style="right:1px"> ' +
            '<button class="inputex_autohidebutton" type="button">×</button>' +
            '</div>';
        setInnerById(idcontainer, strout);
    }
    static selectInputUsersOnSelect(fnCallBackName, idinput, idval, user_id, user_realname, user_address, user_phone) {
        if (isEmpty(user_id)) {
            user_id = "";
            user_realname = "";
            user_address = "";
            user_phone = "";
        }
        setValById(idinput, user_realname);

        setValById(idval, user_id);
        if (!isEmpty(fnCallBackName)) {
            execFn(fnCallBackName, [user_id, user_realname, user_address, user_phone]);
        }
    }
    //su dung datalist, hien thi tuy loai trinh duyet
    static selectInputUsers(idcontainer, idval, strplaceholder, fnCallBackName) {
        if (isEmpty(fnCallBackName)) fnCallBackName = "";
        var idinput = idcontainer + "input";
        var idimagestatus = idcontainer + "imagestatus";
        var iddatalist = idcontainer + "datalist";
        var img = "imgs/salesman.png";
        var strout = '<input autoComplete="off" type="search" placeholder="' + strplaceholder + '" id="' + idinput + '"' +
            ' class="inputex_inputex" type="text" style="padding-right: 26px;"' +
            ' oninput="showWaitStatus(0,\'' + idimagestatus + '\',\'' + img + '\');UiControl.getUserDataList(\'' + idinput + '\',\'' + iddatalist + '\',\'' + idval + "\',\'" + fnCallBackName + '\');" ' +
            ' list="' + iddatalist + '"' +
            '     onchange="this.selectionStart = this.selectionEnd =0;">' +
            '   <span id="' + idimagestatus + '" class="inputex_imagestatus"></span>' +
            '   <div class="inputex_autohidegroup" style="right: 26px;">' +
            '         <button class="inputex_autohidebutton" type="button">×</button>' +
            '   </div>' +
            '   <button class="inputex_button" type="button" ' +
            '   onclick="DlgSelect.showUser(0,' +
            '  \'UiControl.selectInputUsersOnSelect\',[\'' + fnCallBackName + '\',\'' + idinput + '\',\'' + idval + '\']);return false;">::</button>  ' +
            ' </div>' +
            ' <datalist id="' + iddatalist + '">' +
            '     <option data-value="0">' + strplaceholder + '</option>' +
            ' </datalist>' +
            ' <input type="hidden" id="' + idval + '" name="' + idval + '">';

        setInnerById(idcontainer, strout);
        setBackgroundImageById(idimagestatus, img);
    }
    //nshowstyle: 0-find, 1-loading, 2-not found
    static inputTextGoodsCodeBarcodeShowImageStatus(idcontainer, nshowstyle) {
        var idimagestatus = idcontainer + "imagestatus";
        var idimg = document.getElementById(idimagestatus);
        if (nshowstyle == 1) {
            setBackgroundImageById(idimagestatus, "imgs/bt_loading.png");
        } else if (nshowstyle == 2) {
            setBackgroundImageById(idimagestatus, "imgs/bt_notfound.png");
        }
        else {
            setBackgroundImageById(idimagestatus, "imgs/bt_searchcode.png");
        }
    }
    static inputTextGoodsCodeBarcode(idcontainer, idinput, strPlaceholder, fnOnKeyUp, fnScan) {
        var idimagestatus = idcontainer + "imagestatus";
        var img = "imgs/bt_searchcode.png";
        if (isEmpty(strPlaceholder)) strPlaceholder = "nhập/quét mã hàng";
        var strout = '<input placeholder="' + strPlaceholder + '" name="' + idinput + '" id="' + idinput + '"' +
            ' class="inputex_inputex" type="text" style="padding-right: 60px;padding-top:4px;padding-bottom:4px;padding-left:32px"' +
            ' onkeyup="' + fnOnKeyUp + '()">';
        strout +=
            ' <span id="' + idimagestatus + '" class="inputex_imagestatus" style="margin-top:2px"></span>';
        strout +=
            ' <div class="inputex_autohidegroup" style="right:66px"> ' +
            '<button class="inputex_autohidebutton" type="button">×</button>' +
            ' </div>';
        strout += ' <span class="inputex_button"' +
            ' onclick="' + fnScan + '();"' +
            ' style="background:url(\'imgs/barcode.png\') no-repeat;background-size: contain;margin-right:0px;background-position: center;"></span>';
        setInnerById(idcontainer, strout);
        setBackgroundImageById(idimagestatus, img);
    }
    //su dung datalist, hien thi tuy loai trinh duyet
    static selectInputGoods(idcontainer, strPlaceholder, fnOnInputCallBack, fnOnInputCallBackEx, invoice_type) {
        if (isEmpty(fnOnInputCallBack)) fnOnInputCallBack = "";
        if (isEmpty(fnOnInputCallBackEx)) fnOnInputCallBackEx = "";

        var idinput = idcontainer + "input";
        var idinputdatalist = idcontainer + "datalist";
        var idimagestatus = idcontainer + "imagestatus";
        var img = "imgs/bt_find.png";
        if (isEmpty(strPlaceholder)) strPlaceholder = "(nhập tên hàng)";
        //var strout='<div class="inputex" style="width: 100%;">' +
        var strout = '<input placeholder="' + strPlaceholder + '" name="' + idinput + '" id="' + idinput + '"' +
            ' class="inputex_inputex" type="text" style="padding-right: 26px;"' +
            ' list="' + idinputdatalist + '"' +
            ' oninput="showWaitStatus(0,\'' + idimagestatus + '\',\'' + img + '\');UiControl.getGoodsDataList(\'' + idinput + '\',\'' + idinputdatalist + '\',\'' + fnOnInputCallBack + '\',\'' + invoice_type + '\');" ' +
            ' onchange="this.selectionStart = this.selectionEnd =0;">' +
            '   <span id="' + idimagestatus + '" class="inputex_imagestatus"></span>' +
            '<div class="inputex_autohidegroup" style="right:26px"> ' +
            '<button class="inputex_autohidebutton" type="button">×</button>' +
            '</div>';

        if (!isEmpty(fnOnInputCallBackEx))
            strout += '<button class="inputex_button"' +
                'onclick="DlgSelect.iddivshow=null;DlgSelect.showGoods(1,\'' + fnOnInputCallBackEx + '\');"  type="button">::</button>';
        strout += '<datalist id="' + idinputdatalist + '">';
        strout += '</datalist>';

        setInnerById(idcontainer, strout);
        setBackgroundImageById(idimagestatus, img);
    }
    static inputWithClearButtonSetup() {
        const inputs = document.querySelectorAll(".inputex_input")
        const handleInputChange = (e) => {

            inputs.forEach(input => {
                if (input.id == e.currentTarget.myparam) {
                    if (e.target.value && !input.classList.contains("inputex_autohidegroup_touched")) {
                        input.classList.add("inputex_autohidegroup_touched")
                    }
                    else if (!e.target.value && input.classList.contains("inputex_autohidegroup_touched")) {
                        input.classList.remove("inputex_autohidegroup_touched")
                    }
                }

            });

        }
        inputs.forEach(input => {
            input.addEventListener("input", handleInputChange, false)
            input.myparam = input.id;
        });

        const clearButtons = document.querySelectorAll(".inputex_autohidebutton")
        const handleButtonClick = (e) => {
            inputs.forEach(input => {
                if (input.id == e.currentTarget.myparam) {
                    input.value = ''
                    input.focus()
                    input.classList.remove("inputex_autohidegroup_touched")
                }

            });

        }
        clearButtons.forEach(clearButton => {
            clearButton.addEventListener("click", handleButtonClick, false)
            clearButton.myparam = clearButton.parentElement.previousElementSibling.id;

        });
    }
    static inputWithClearButtonOnInput(idinput) {
        var e = window.event;
        const input = document.getElementById(idinput);
        if (isEmpty(e)) {
            if (!input.classList.contains("inputex_autohidegroup_touched")) {
                input.classList.add("inputex_autohidegroup_touched")
            } else if (input.classList.contains("inputex_autohidegroup_touched")) {
                input.classList.remove("inputex_autohidegroup_touched")
            }
            return;
        }
        //const input = document.querySelector(".inputex_input");


        if (e.target.value && !input.classList.contains("inputex_autohidegroup_touched")) {
            input.classList.add("inputex_autohidegroup_touched")
        } else if (!e.target.value && input.classList.contains("inputex_autohidegroup_touched")) {
            input.classList.remove("inputex_autohidegroup_touched")
        }
    }
    static inputWithClearButtonOnClear(idinput) {
        const input = document.getElementById(idinput);
        if (input === null) return;
        input.value = '';
        input.focus();
        input.classList.remove("inputex_autohidegroup_touched");
    }
    //hien thi danh sach dang datalist-html
    static getContactDataList(idinput, iddatalist, idselectedcontact) {
        //var key, x = e || window.event; key = (x.keyCode || x.which);
        //if(!isVisiableKeyCode(key))
        //   return;
        //neu nhan chon lua
        var val = document.getElementById(idinput).value;
        var opts = document.getElementById(iddatalist).children;
        for (var i = 0; i < opts.length; i++) {
            if (opts[i].value === val) {
                // An item was selected from the list!
                // yourCallbackHere()
                var val = opts[i].getAttribute('data-value');
                if (parseNumberVn(val) > 0)
                    setValById(idselectedcontact, val);
                else
                    setValById(idselectedcontact, 0);
                showWaitStatus();
                return;
            }
        }
        var search_key = uriEncode(getValById(idinput));
        var url = "?page=list&pagesub=contact_searchshort&contactname=" + search_key;

        var dataString = "";
        jQuery.ajax({
            url: url,
            data: dataString,
            type: "GET",
            success: function (data) {
                if (isDataFail(data)) {
                    showMsg(getDataFail(data));
                    return;
                }
                else if (isDataOk(data)) {
                    var rows = getDataOk(data).split(g_split_row);
                    var dataset = "";
                    for (i = 0; i < rows.length; i++) {
                        if (rows[i].substr(0, g_sign_columnconfig.length) == g_sign_columnconfig)
                            continue;
                        var vals = rows[i].split(g_split_val);
                        var fname = vals[1];
                        if ((vals[2] !== undefined) && (vals[2].length > 0))
                            fname += " (" + vals[2] + ")";
                        if ((vals[3] !== undefined) && (vals[3].length > 0))
                            fname += " (" + vals[3] + ")";
                        dataset += "<option data-value='" + vals[0] + "'>" + fname + "</option>";
                    }
                    setInnerById(iddatalist, dataset);
                    showWaitStatus();
                }
                else
                    showMsg(itxt("loi"));
                showWaitStatus();
            },
            error: function () {
                showMsg(itxt("loi"));
                showWaitStatus();
            }
        });
    }
    //datalist-html (id-name)
    static getGoodsDataList(idinput, iddatalist, fnCallBackName, invoice_type) {
        //neu nhan chon lua
        var val = document.getElementById(idinput).value;
        var opts = document.getElementById(iddatalist).children;
        for (var i = 0; i < opts.length; i++) {
            if (opts[i].value === val) {
                var val = opts[i].getAttribute('data-value');
                eval(fnCallBackName)(val);
                showWaitStatus();
                return;
            }
        }

        var search_key = uriEncode(getValById(idinput));
        var url = "?page=list&pagesub=goods&invoice_type=" + invoice_type + "&goods_name=" + search_key;
        var dataString = "";
        jQuery.ajax({
            url: url,
            data: dataString,
            type: "GET",
            success: function (data) {

                data = getDataOk(data);
                var rows = data.split(g_split_row);
                var dataset = "";
                for (i = 0; i < rows.length; i++) {
                    if (rows[i].substr(0, g_sign_columnconfig.length) == g_sign_columnconfig)
                        continue;
                    if (rows[i].substr(0, g_sign_pageconfig.length) == g_sign_pageconfig)
                        continue;
                    var vals = rows[i].split(g_split_val);
                    var goods_id = vals[1], unit_id = vals[2];
                    var fname = vals[3];
                    if ((vals[7] !== undefined) && (vals[7].length > 0))
                        fname += " (" + vals[7] + ")";
                    if ((vals[5] !== undefined) && (vals[5].length > 0))
                        fname += " (" + vals[5] + ")";

                    dataset += "<option data-value='" + rows[i] + "'>" + fname + "</option>";
                }

                setInnerById(iddatalist, dataset);
                showWaitStatus();
                hideModal();

            },
            error: function () {
                showMsg(itxt("loi"));
                showWaitStatus();
            }
        });
    }
    //datalist-html (id-name)
    static getUserDataList(idinput, iddatalist, idval, fnCallBackName) {
        //neu nhan chon lua
        var val = document.getElementById(idinput).value;
        var opts = document.getElementById(iddatalist).children;

        for (var i = 0; i < opts.length; i++) {
            if (opts[i].value === val) {
                var valselected = opts[i].getAttribute('data-value');

                if (!isEmpty(fnCallBackName)) eval(fnCallBackName)(valselected);
                setValById(idval, valselected);
                showWaitStatus();
                return;
            }
        }
        var search_key = uriEncode(getValById(idinput));
        var url = "?page=list&pagesub=employee";

        var dataString = "";
        jQuery.ajax({
            url: url,
            data: dataString,
            type: "GET",
            success: function (data) {
                var rows = getDataOk(data).split(g_split_row);
                var dataset = "";
                for (i = 0; i < rows.length; i++) {
                    if (rows[i].substr(0, g_sign_columnconfig.length) == g_sign_columnconfig)
                        continue;
                    if (rows[i].substr(0, g_sign_pageconfig.length) == g_sign_pageconfig)
                        continue;
                    var vals = rows[i].split(g_split_val);
                    var user_id = vals[0], realname = vals[1];
                    var address = vals[2], mobile = vals[3];
                    dataset += "<option data-value='" + vals[0] + "'>" + realname + "</option>";
                }
                setInnerById(iddatalist, dataset);
                showWaitStatus();
                hideModal();

            },
            error: function () {

                showMsg(itxt("loichuaxacdinh"));
                showWaitStatus();
            }
        });
    }

}

//*END_CLASS_DLG_SELECT
//START:UIListBoxEx
class UIListBoxEx {
    /*
    Event:
    *onSelect: select and hide list item
    *onSelectM: select and not hide list item
    *onGetData
    *onCmd
    Properties:
    label_place_holder
    label_select_one
    combobox_mode: select and close
    var data_struct=[
            {name:"id",head:"",visible:0,idsub:1/2..},
            {name:"name/data.."  ,head:"HEAD",visible:0/1/2,type:"text/check/number",required:1/0,merge:"1"},
    ];
    */
    constructor(objectInstanceName, in_data_struct) {
        this.objInstanceName = objectInstanceName;//ten bien global scope cua doi tuong duoc tao ra
        this.data_struct = in_data_struct;
        this.input_mode = 0;//default:search
        this.onGetData = null;
    }
    onclickimagestatus() {
        //if (isEmpty(this.icon)) this.icon = "imgs/bt_find.png";
        this.input_mode++;
        if (this.input_mode > 2) this.input_mode = 0;
        if (this.input_mode == 0)
            setBackgroundImageById(this.idimagestatus, "imgs/bt_find.png");
        else if (this.input_mode == 1)
            setBackgroundImageById(this.idimagestatus, "imgs/bt_searchcode.png");
        else
            setBackgroundImageById(this.idimagestatus, "imgs/bt_deny.png");
    }
    hideList() {
        if (this.isListVisibled()) {
            if (!isEmpty(g_dropdowndiv)) {
                g_dropdownrect = null;
                g_dropdowndiv.style.display = "none";
                return;
            }
            return;
        }
    }
    //show-hide
    onclick() {
        if (this.isListVisibled()) {
            if (!isEmpty(g_dropdowndiv)) {
                g_dropdownrect = null;
                g_dropdowndiv.style.display = "none";
                return;
            }
            return;
        }
        if (this.input_mode == 2) return;
        var idimagestatus = this.idcontainer + "imagestatus";
        var image = this.icon;
        if (this.input_mode == 1) image = this.iconcode;
        else if (this.input_mode == 2) image = this.icondeny;
        showWaitStatus(0, idimagestatus, image);
        if (!isEmpty(this.onGetData)) {
            eval(this.onGetData)(this.idinput, this.input_mode);
        }

    }
    onkeydowninput() {

        if ((event.key == "Escape") || (event.key == "Tab")) {
            g_dropdowndiv = null;
            g_dropdownrect = null;
            var idContent = document.getElementById(this.idContent);
            idContent.style.display = "none";
            setValById(this.idinput, "");
        } else if (event.key == "Enter") {
            if (this.selectIndex < 0) return;
            if (isEmpty(this.rows)) return;
            if (this.selectIndex >= this.rows.length) return;
            this.onItemSelect(this.selectIndex);
        } else if (event.key == "ArrowDown") {
            if (this.selectIndex >= (this.rows.length - 1)) {
                return;
            }
            var idcur = document.getElementById(this.getRowId(this.selectIndex));
            idcur.className = "divrow";

            this.selectIndex += 1;
            var idsel = document.getElementById(this.getRowId(this.selectIndex));
            idsel.className = "divrow selected";

            if (!isEleVisible(idsel, document.getElementById(this.idContent))) {
                idsel.scrollIntoView();
            }
        } else if (event.key == "ArrowUp") {
            if (this.selectIndex <= 0) return;
            if (isEmpty(this.rows)) return;
            if (this.rows.length < 1) return;

            var idcur = document.getElementById(this.getRowId(this.selectIndex));
            idcur.className = "divrow";

            this.selectIndex -= 1;
            var idsel = document.getElementById(this.getRowId(this.selectIndex));
            idsel.className = "divrow selected";
            if (!isEleVisible(idsel, document.getElementById(this.idContent))) {
                idsel.scrollIntoView();
            }
        }
    }
    oninput() {
        if (this.input_mode == 2) return;
        var image = this.icon;
        if (this.input_mode == 1) image = this.iconcode;
        else if (this.input_mode == 2) image = this.icondeny;
        showWaitStatus(0, this.idimagestatus, image);
        eval(this.onGetData)(this.idinput, this.input_mode);
    }
    show(idcontainer) {
        this.idcontainer = idcontainer;
        this.idinput = idcontainer + "input";//display
        this.idinputdata = idcontainer + "inputdata";//hidden hold id value
        this.idbuttonmic = idcontainer + "buttonmic";
        this.idbuttonmore = idcontainer + "buttonmore";
        this.idContent = idcontainer + "content";
        this.idimagestatus = idcontainer + "imagestatus";
        if (isEmpty(this.icon)) this.icon = "imgs/bt_find.png";
        this.iconcode = "imgs/bt_searchcode.png";
        this.icondeny = "imgs/bt_deny.png";
        var padding_right = 42;//mic
        if (!isEmpty(this.onCmd)) padding_right = 82;
        if (isEmpty(this.label_place_holder)) this.label_place_holder = "(..)";
        if (isEmpty(this.label_cmd)) this.label_cmd = "::";
        var nRight = 0;
        var strout = "";
        strout += '<span onclick="' + this.objInstanceName + '.onclickimagestatus()" id="' + this.idimagestatus + '" class="inputex_imagestatus"></span>';
        strout += '<input placeholder="' + this.label_place_holder + '" name="' + this.idinput + '" id="' + this.idinput + '"' +
            ' class="inputex_inputex" type="search" style="padding-right: ' + padding_right + 'px;"' +
            ' onkeydown="' + this.objInstanceName + '.onkeydowninput();"' +
            ' onfocus="this.selectionStart =0; this.selectionEnd=-1;"' +
            ' onclick="' + this.objInstanceName + '.onclick();"' +
            ' oninput="' + this.objInstanceName + '.oninput();"' +
            ' onchange="this.selectionStart = this.selectionEnd =0;">';
        strout += '<input type="hidden" id="' + this.idinputdata + '">';
        if (!isEmpty(this.onCmd)) {
            strout += '<div class="inputex_button" style="right:0px" ' +
                'onclick="' + this.objInstanceName + '.hideList();' + this.onCmd + '();">' + this.label_cmd + '</div>';
            nRight = 40;
        }
        if (typeof SpeechRecognition !== "undefined")
            strout += '<div class="inputex_button speech" id=\"' + this.idbuttonmic + '\" style="right:' + nRight + 'px" onclick="speechStart(\'' + this.idinput + "\',\'" + this.idbuttonmic + '\')"></div>';

        strout += '<div class="dropdown-content combo" onfocus=";" style="width:100%;overflow:auto;display:none;margin-top:2px" id="' + this.idContent + '"></div>';

        setInnerById(idcontainer, strout);
        setBackgroundImageById(this.idimagestatus, this.icon);
    }
    onItemSelect(i) {
        if (isEmpty(this.rows)) return;
        if (i < 0) return;
        if (i >= this.rows.length) return;
        var vals = this.rows[i].split(g_split_val);

        execFn(this.onSelect, vals);
        if (!isEmpty(this.combobox_mode)) {
            //find first label
            var label = "";
            for (var i = 0; i < this.data_struct.length; i++) {
                if (dsIsVisible(this.data_struct, i)) {
                    label = vals[i];
                    break;
                }
            }
            setValById(this.idinput, label);
            g_dropdownrect = null;
            g_dropdowndiv.style.display = "none";
        }

    }
    onClearSelect() {
        setValById(this.idinput, "");
    }
    getRowId(index) {
        return "uilistboxex_rowid_" + index;
    }
    getVal() {
        return getValById(this.idinput);
    }
    getData() {
        return getValById(this.idinputdata);
    }
    setVal(display, data) {
        setValById(this.idinput, display);
        setValById(this.idinputdata, data);
    }
    isListVisibled() {
        var idContent = document.getElementById(this.idContent);
        return idContent.style.display == "block";
    }
    //boverlay:true -> display over other element, false: make space and push other element down
    showList(rows, boverlay = false) {
        this.rows = rows;
        var allrows = "", cmd = "", rowclass = "";

        for (var i = 0; i < rows.length; i++) {
            var data_vals = rows[i].split(g_split_val);
            cmd = this.objInstanceName + ".onItemSelect(" + i + ");";
            if (i == 0) {
                this.selectIndex = 0;
                rowclass = "divrow selected";
            } else {
                rowclass = "divrow";
            }
            allrows += "<div id=\"" + this.getRowId(i) + "\" class=\"" + rowclass + "\" onclick=\"" + cmd + "\">";
            for (var j = 1; j < data_vals.length; j++) {
                if (dsIsVisible(this.data_struct, j)) {
                    var classCell = "divcell", value = data_vals[j];
                    if (!isEmpty(this.data_struct[j].class)) classCell += " " + this.data_struct[j].class;
                    allrows += "<div class=\"" + classCell + "\" style=\"width:" + dsGetWidth(this.data_struct, j);
                    if (this.data_struct[j].type == "number") {
                        allrows += ";text-align:right;";
                        value = formatNumberZS(value);
                    }
                    allrows += "\">" + escapeHTML(value);
                    if (!isEmpty(this.data_struct[j].subinfo)) {
                        for (var k = 0; k < this.data_struct[j].subinfo.length; k++) {
                            var index = this.data_struct[j].subinfo[k];
                            var subinfoclass = 'subinfo';
                            if (!isEmpty(this.data_struct[j].subinfoclass)) {
                                subinfoclass = this.data_struct[j].subinfoclass;
                            }
                            if (!isEmpty(this.data_struct[index].class)) subinfoclass += (" " + this.data_struct[index].class);
                            if (!isEmpty(data_vals[index].length)) {
                                if (!isEmpty(this.data_struct[index].subinfobreak))
                                    allrows += this.data_struct[index].subinfobreak;
                                else
                                    allrows += "<br>";
                                allrows += "<span class='" + subinfoclass + "'>" + escapeHTML(data_vals[index]) + "</span>";
                            }

                        }

                    }
                    allrows += "</div>";
                }
            }
            //var button="<input type=\"button\" class=\"buttonincell selectimage\" placeholder=\""+this.label_select_one+"\" onclick=\"event.stopPropagation();setModalHeading('OK');"+cmd+"\">";
            //allrows+="<div class=\"divcell padding0\" style=\"width:"+g_ui_cmdwidth+"px\">"+button+"</div>";
            allrows += "</div>";
        }
        allrows = "<div class='divtable'>" + allrows + "</div>";

        var idinput = document.getElementById(this.idinput);
        var rcinput = idinput.getBoundingClientRect();

        var idContent = document.getElementById(this.idContent);
        idContent.innerHTML = allrows;
        idContent.style.display = "block";
        if (boverlay) {
            idContent.style.top = (rcinput.bottom - rcinput.top) + "px";
            idContent.style.position = "absolute";
        }
        else {
            idContent.style.top = "0px";
            idContent.style.position = "relative";

        }
        idContent.style.zIndex = "10";
        idContent.style.height = "300px";
        idContent.style.background = "#3399FF";

        var rccontent = idContent.getBoundingClientRect();
        if (!isEmpty(g_dropdownrect)) {
            g_dropdownrect.top = rcinput.top;
            g_dropdownrect.left = rcinput.left;
            g_dropdownrect.right = rccontent.right;
            g_dropdownrect.bottom = rccontent.bottom;
        }
        else {
            g_dropdownrect = new UIRect(rcinput.top, rcinput.left, rccontent.right, rccontent.bottom);
        }
        g_dropdowndiv = idContent;

    }
}
class UIRect {
    constructor(top, left, right, bottom) {
        this.top = top; this.left = left; this.right = right; this.bottom = bottom;
    }
}
/*TRANS_TYPE
GOODS: goods_id,goods_name,goods_code,unit_name,unit_id,category_name,category_id,export_price,wholesale_price,is_material,is_product
GOODS_EXIM: goods_id,goods_name,goods_code,unit_name,unit_id,quantity,unit_price,discount,serial
INVOICE: invoice_id,invoice_no,invoice_date,reason,reason_other,comment,contact_id,contact_name,contact_address,contact_phone,sale_id,sale_realname
*/


defineStaticField(DlgSelect, "page_source", "");
defineStaticField(DlgSelect, "page_title", "");
defineStaticField(DlgSelect, "last_goods_category_id", 0);
defineStaticField(DlgSelect, "iddivshow", null);
defineStaticField(DlgSelect, "showlistheading", 1);
defineStaticField(DlgSelect, "pagesize", 20);

defineStaticField(GridViewEx, "objInstanceName", "");
defineStaticField(GridViewEx, "data_struct", null);
defineStaticField(GridViewEx, "page_source", "");
defineStaticField(GridViewEx, "page_title", "");
defineStaticField(GridViewEx, "show_collapsiblerow", 0);
defineStaticField(GridViewEx, "editfrom_header", "");
defineStaticField(GridViewEx, "editform_content", "");
defineStaticField(GridViewEx, "editfrom_firstfocus", "");
defineStaticField(GridViewEx, "m_fnCmd", null);
defineStaticField(GridViewEx, "m_fnCmdTitle", null);
defineStaticField(GridViewEx, "m_fnCmdParams", null);
defineStaticField(GridViewEx, "active_param", null);
