/*
 * Copyright (c) 2001-2014,FineReport Inc, All Rights Reserved.
 */

/**
 * 生成填报页面的所有控件,绑定事件,提供参数联动等。
 * @class FR.Write
 * @extends FR.OB
 */
FR.Write = FR.extend(FR.OB, {
    _init: function () {
        //b:初始化只初始widget
        FR.Write.superclass._init.apply(this, arguments);

        /**
         * @property {Map} location_widgets 位置和控件组成的键值对集合
         */
        this.location_widgets = {};
        this.name_widgets = {};

        var self = this;
        var selector = this.options.selector || 'td[widget]';
        if (typeof selector == "string") {
            $(selector, this.options.renderEl).each(function (idx, dom) {
                if ($.data($(dom), "__initialized__") !== true) {
                    self.addWidget($(dom));
                }
            })
        }
    },

    /**
     * Widget管理对象
     */
    WidgetMgr: {
        DependenceMgr: {
            //被依赖location -> 依赖location数组,A2,A3控件依赖A1控件,则dependenceMap["A1"]->["A2","A3"]
            _dependenceRelationMap: {},
            //location -> boolean,保存有依赖属性的控件有没有初始化
            _dependenceInitedMap: {},
            //需要马上添加依赖关系的。主要是带widget属性的如单选按钮组。
            _shouldInitAtOnce: [],
            /**
             * 添加依赖关系
             * @param location 被依赖的控件位置
             * @param dependenceLocation 带依赖属性控件的位置
             */
            addDependenceRelation: function (location, dependenceLocation) {
                if (typeof location === "string") {
                    location = location.toUpperCase();
                }
                var dependenceRelation = this._dependenceRelationMap[location];
                if (!dependenceRelation) {
                    dependenceRelation = [];
                    this._dependenceRelationMap[location] = dependenceRelation;
                }
                dependenceRelation.push(dependenceLocation);

            },
            /**
             * 获取依赖关系
             * @param location 被依赖的控件位置
             * @returns {*} 返回带依赖属性控件的位置数组
             */
            getDependenceRelation: function (location) {
                if (typeof location === "string") {
                    location = location.toUpperCase();
                }
                return this._dependenceRelationMap[location];
            },
            /**
             * 标识已经初始化
             * @param location 带依赖属性控件的位置
             */
            setInited: function (location) {
                this._dependenceInitedMap[location] = true;
            },
            /**
             * 判断是否初始化
             * @param location 带依赖属性控件的位置
             * @returns {boolean} 是否初始化
             */
            isInited: function (location) {
                return !FR.isNull(this._dependenceInitedMap[location]);
            },

            /**
             * 添加要初始化依赖关系的控件
             * @param location 控件
             */
            addWidgetShouldInitDependence: function (location) {
                this._shouldInitAtOnce[this._shouldInitAtOnce.length] = location;
            },

            /**
             * 获取要初始化依赖关系的控件
             * @returns {*}
             */
            getWidgetShouldInitDependence: function () {
                return this._shouldInitAtOnce;
            }

        }
    },
    /**
     * 将控件注册到控件位置集合(location_widgets)和控件名集合(name_widgets)中去
     * @param {FR.Widget} editor 要注册的控件
     */
    addEditor: function (editor) {
        if (editor.options.location && this.location_widgets[editor.options.location]===undefined) {
            this.location_widgets[editor.options.location] = editor;
        }
        if (editor.options.widgetName) {
            this.pushNameWidget(editor.options.widgetName, editor);
        }
    },

    /**
     * 单元格初始化控件,绑定事件并标记已初始化。
     * @param $dom {$} 单元格DOM元素
     */
    addWidget: function ($dom) {
        this.addLocationWidget($dom, FR.jsonDecode($dom.attr('widget')));
        // richie:标记一下这个dom节点上的控件已经初始化
        $.data($dom, "__initialized__", true);
    },

    addWriteWidget: function ($dom) {
        this.addLocationWidgetWithoutWriteEvent($dom, FR.jsonDecode($dom.attr('editor')));
    },

    /**
     * 单元格初始化控件。只在指定DOM里生成控件,不绑定事件。
     * @param {jQuery} $dom 单元格DOM元素
     * @param {JSON} editorConfig 控件配置属性
     */
    addLocationWidgetWithoutWriteEvent: function ($dom, editorConfig) {
        //zack:直接显示控件且控件带超链,超链优先,但是只是文本类控件的场景
        if($dom.is('.celink') && editorConfig.isEditable){
            return;
        }
        if(editorConfig.isEditable){
            editorConfig.width = Math.max($dom.width(),$dom.attr("widgetWidth"));
            //ie8以下版本边框重合不起来这边高度需要减掉文本框下边框的1像素
            var widgetHeight=Math.max($dom.height(),$dom.attr("widgetHeight"));
            //bug74266,chorme下边框会有问题如果控件高度和TD高度一样会出现奇怪现象。
            editorConfig.height = FR.Browser.isIE8Before() || FR.Browser.r.webkit ? widgetHeight - 1 : widgetHeight;
        }else{
            editorConfig.width = $dom.attr("widgetWidth");
            editorConfig.height = $dom.attr("widgetHeight");
        }

        $.extend(editorConfig, {
            write: this
        });
        var $editor = $("<div/>").appendTo($dom);
        editorConfig.renderEl = $editor;
        if (editorConfig['jspath']) {
            var arr = editorConfig['jspath'].split(";");
            $.each(arr, function (i, item) {
                FR.$import(item, "js");
            });
        }
        if (editorConfig['csspath']) {
            var arr = editorConfig['csspath'].split(";");
            $.each(arr, function (i, item) {
                FR.$import(item, "css");
            });
        }
        editorConfig.border = $dom.border();
        if (editorConfig.isEditable) {
            if (editorConfig.type == 'multifile') {
                $.extend(editorConfig, {
                    tdCell: $dom
                });
            }
            var editContent = this.getEditContent($dom);
            var val;
            var fmt = $dom.attr('fmt');
            if (this.isDateContent(editContent, editorConfig)) {
                fmt = fmt || 'DMM/dd/yyyy'; //这边只有日期会有默认的fmt
                val = FR.contentFormat(editContent.date_milliseconds, fmt);
            } else {
                val = FR.contentFormat(editContent, fmt);
            }
            val =  val ||  $dom.attr('displayValue') ;
            if (val) {
                $.extend(editorConfig, {
                    value: val,
                    showValue:  $dom.attr('displayValue') || val
                });
            }
        }

        var editorEl = FR.createWidget(editorConfig);
        if(editorConfig.isEditable){
            editorEl.cssFrom($dom,editorConfig.isEditable);
        }

        this.addEditor(editorEl);
    },
    isDateContent: function (editContent, editorConfig) {
        return this.isDateTypeButNotDateTimeContent(editContent, editorConfig) || this.isDateDateTimeContent(editContent, editorConfig);
    },
    isDateTypeButNotDateTimeContent : function(editContent , editorConfig){
        return editContent && editContent.date_milliseconds
            && editorConfig && editorConfig.type != "datetime";
    },

    isDateDateTimeContent : function(editContent , editorConfig){
        return editContent && editContent.date_milliseconds
            && editorConfig && editorConfig.type === "datetime";
    },
    getEditContent : function ($tdCell){
        var editContent;
        if(FR.isEmpty($tdCell)){
            return;
        }
        if ((editContent = $tdCell.attr('cv')) != null) {
            return FR.jsonDecode(editContent);
        } else if ($tdCell.attr('widget')) {
            return $tdCell.attr('cv');
        } else {
            return $tdCell.hasClass("watermarkCell") ? "" : $tdCell.text();
        }
    },
    /**
     * 单元格初始化控件并绑定事件
     * @param {jQuery} $dom 单元格DOM元素
     * @param {JSON} editorConfig 控件的配置属性
     */
    addLocationWidget: function ($dom, editorConfig) {
        this.addLocationWidgetWithoutWriteEvent($dom, editorConfig);

        if (editorConfig.location && !editorConfig.isEditable) {
            this.widgetOnWriteEvent(this.location_widgets[editorConfig.location]);
        }
    },

    /**
     * 将控件添加进控件名集合中
     * @param {String} widgetName 控件名
     * @param {FR.Widget} widget 控件
     */
    pushNameWidget: function (widgetName, widget) {
        var name = widgetName.toUpperCase().perfectStart("$");
        if (!this.name_widgets[name]) {
            this.name_widgets[name] = widget;
        } else {
            if (FR.isArray(this.name_widgets[name])) {
                for (var i = 0; i < this.name_widgets[name].length; i++) {
                    if (this.name_widgets[name][i].options.widgetUrl == widget.options.widgetUrl) {
                        return;
                    }
                }
                this.name_widgets[name].push(widget);
            } else {
                if (this.name_widgets[name].options.widgetUrl != widget.options.widgetUrl) {
                    this.name_widgets[name] = [this.name_widgets[name], widget];
                }
            }
        }
    },

    /**
     * 为控件绑定事件
     * @param {FR.Widget} widget 控件对象
     */
    widgetOnWriteEvent: function (widget) {
        widget.on(FR.Events.BEFORESTATECHANGE, function () {
            if (this.isEnabled()) {
                if (!_g(this.options.sessionID).curLGP.stopCellEditing()) {
                    return false;
                }
            }
        });
        widget.on(FR.Events.STATECHANGE, function () {
            // 不管校验成功与否,都应该执行fireCellValueChange,不然generateReportXML的值会与实际值不一致
            _g(this.options.sessionID).curLGP.fireCellValueChange(_g(this.options.sessionID).curLGP.getWidgetCell(this), this.getValue());
            if (!this.isValidate()) {
                FR.Msg.toast(this.getErrorMessage());
                return false;
            }
        });
    },
    /**
     * 处理联动的方法
     * @param variable {*} 联动参数
     * @returns {*}
     */
    resolveVariable: function (variable) {
        if ($.isFunction(this.options.resolveVariable)) {
            return this.options.resolveVariable(variable);
        }
    },

    /**
     * 根据单元格位置获取单元格中的控件
     * e.g. 获取单元格A1中的控件contentPane.getWidgetByCell('A1');
     * @param {String} location 单元格的位置,如C2,A7
     * @param {FR.Widget[]} widgets 控件集合,该参数不必要
     * @returns {FR.Widget} 控件
     */
    getWidgetByCell: function (location, widgets) {
        if (!this.location_widgets || !location) {
            return null;
        }
        return this.location_widgets[location] || this._findLocationWidget(location, widgets);
    },

    /**
     * 根据控件名字获取控件
     * e.g. 获取名字为p1的控件 contentPane.getWidgetByName('p1')
     * @param {String} name 要获取的控件所具有的控件名
     * @returns {FR.Widget} 控件
     */
    getWidgetByName: function (name) {
        if (!name) {
            return null;
        }
        name = ((name.indexOf("$") !== 0) ? '$' + name : name).toUpperCase();
        // 必须先从已有的开始找 构建两次就不是同一个了对象了
        return (FR.isArray(this.name_widgets[name]) ? (this.name_widgets[name])[0] : this.name_widgets[name])
            || this._findNameWidget(name);
    },

    /**
     * 根据控件名获取具有同一名字的控件数组的集合
     * e.g. 获取名字为p1的所有控件组成的数组 contentPane.getWidgetsByName('p1')
     * @param {String} name 要获取的控件所具有的控件名
     * @returns {FR.Widget[]} 控件数组
     */
    getWidgetsByName: function (name) {
        if (!name) {
            return;
        }
        name = ((name.indexOf("$") !== 0) ? '$' + name : name).toUpperCase();
        // 必须先从已有的开始找 构建两次就不是同一个了对象了
        return this.name_widgets[name] || this._findNameWidget(name, true);
    },

    _findTDByLocation: function (location) {
        return $('td[id^=' + location + '-]', this.options.renderEl);
    },

    _findLocationWidget: function (location, widgetsSrc) {
        /**
         * 在所给控件集合中找到指定单元格位置的控件
         * @param {String} location 单元格的位置
         * @param {Array} widgetsSrc 控件集合
         * @returns {FR.Widget} 返回找到的控件
         * @private
         */
        var widgets;
        if (widgetsSrc !== undefined) {
            widgets = widgetsSrc;
        } else {
            if (!FR.isValidCellStr(location)) {
                return null;
            }
            widgets = this._findTDByLocation(location);
        }
        for (var i = 0, len = widgets.length; i < len; i++) {
            var config = FR.jsonDecode($(widgets[i]).attr('editor'));
            if (config.location == location) {
                $.extend(config, {
                    write: this,
                    //b:太别扭了,以后会widget直接resize即可
                    //获取offsetWidth会导致reflow,在这里初始化的一般都会resize,暂时去掉,看看有什么问题
                    width: widgets[i].offsetWidth + _g().curLGP.getewadjst(),
                    height: widgets[i].offsetHeight + _g().curLGP.getehadjst()
                });
                if (config.type == 'multifile') {
                    $.extend(config, {
                        tdCell: this.lgp.writePane.curLGP._get$TDCell(location)
                    });
                }
                this.addEditor(FR.createWidget(config));
                this._initDependenceRelationWidgetByKey(config.location);
                this._initDependenceRelationWidgetByKey(config.widgetName);
                return this.location_widgets[location];
            }
        }
    },

    /**
     * 初始化依赖控件
     * @param key DependenceMgr中relationMap中的键,可以是控件位置或者控件名称
     * @private
     */
    _initDependenceRelationWidgetByKey: function (key) {
        if (!key) {
            return;
        }
        var dependenceRelation = this.WidgetMgr.DependenceMgr.getDependenceRelation(key);
        this._initDependenceRelationWidget(dependenceRelation);
    },
    /**
     * 初始化依赖控件
     * @param dependenceRelation 依赖控件的位置数组
     * @private
     */
    _initDependenceRelationWidget: function (dependenceRelation) {
        if (dependenceRelation) {
            for (var i = 0; i < dependenceRelation.length; i++) {
                var location = dependenceRelation[i];
                if (this.WidgetMgr.DependenceMgr.isInited(location)) {
                    continue;
                }
                this.WidgetMgr.DependenceMgr.setInited(location);
                var widget = this.getWidgetByCell(location);
                if (widget == null) {
                    continue;
                }
                if (widget.options.dependenceMap) {
                    $.each(widget.options.dependenceMap, this._initCellValueChange, [this, widget]);
                } else if (FR.isArray(widget.options.dependence)) {
                    $.each(widget.options.dependence, this._initCellValueChange, [this, widget]);
                }
            }
        }
    },
    _initCellValueChange: function (fr_write, cur_widget) {
        var item = this;
        var self = fr_write.lgp;
        if (!cur_widget) {
            return;
        }
        var idOrName = item.startWith("$") ? item.substring(1) : item;
        var depId = idOrName + "-" + self.idx + "-" + self.tableID;
        var depWidget = fr_write.getWidgetByCell(idOrName) || fr_write.getWidgetByName(idOrName);
        if (depWidget) {
            depWidget.on(FR.Events.AFTEREDIT, function () {
                self.resetCellValue(this);
                this.reset();
                if (!this.couldUsedAsEditor()) {
                    this.element.show();
                }
            }.createDelegate(cur_widget));
        }
        ;
        self.on(FR.Events.CELLVALUECHANGE, function (cell, value) {
            // richer:由于这里采用的是WLGP的事件来进行联动的,所以要避免死循环
            var cellWidget = FR.jsonDecode(cell.attr("editor") || cell.attr("wdiget"));
            if ((cell.attr("id") == depId) || (cellWidget.widgetName ? (cellWidget.widgetName.toUpperCase() == idOrName.toUpperCase()) : false)) {
                self.resetCellValue(this);
                this.reset();
                if (!this.couldUsedAsEditor()) {
                    this.element.show();
                }
                return false;
            }
        }.createDelegate(cur_widget));
    },

    _findNameWidget: function (name, multi) {
        //有插入行按钮动态增加控件, 不能缓存, 如果遍历下所有控件, 寻找有没有插入行按钮, 性能也不快.
        var widgets = $('td[editor]', this.options.renderEl);
        for (var i = 0, len = widgets.length; i < len; i++) {
            // 删除行的就去掉
            if ($(widgets[i]).hasClass("del")) {
                continue;
            }
            var config = FR.jsonDecode($(widgets[i]).attr('editor'));
            if (!config.widgetName) {
                continue;
            }

            var tempName = ((config.widgetName.indexOf("$") !== 0) ? '$' + config.widgetName : config.widgetName).toUpperCase();
            if (tempName == name) {
                $.extend(config, {
                    write: this
                    //b:太别扭了,以后会widget直接resize即可
                    //width: widgets[i].offsetWidth + _g().curLGP.getewadjst(),
                    //height: widgets[i].offsetHeight + _g().curLGP.getehadjst()
                });
                this.addEditor(FR.createWidget(config));
                this._initDependenceRelationWidgetByKey(config.location);
                this._initDependenceRelationWidgetByKey(config.widgetName);
                if (!multi) {
                    return this.name_widgets[name];
                }
            }
        }
        return this.name_widgets[name];
    },

    // after append or delete row
    // 数据量大的时候影响效率 改成增删行只改变对应行中的控件比较合适
    refreshWidget: function () {

    }
});
$.shortcut("fr_write", FR.Write);

/**
 * 填报控件的接口,为填报中使用的控件添加公共的函数,按钮、复选框之类的即时显示的控件不需要继承此类
 * @class FR.WriteEditor
 * @extends FR.BaseEditor
 */
FR.WriteEditor = FR.extend(FR.BaseEditor, /**@class FR.WriteEditor*/{
    _defaultConfig: function () {
        return $.extend(FR.WriteEditor.superclass._defaultConfig.apply(), {
            usedAsEditor: true
        });
    },

    _init: function () {
        FR.WriteEditor.superclass._init.apply(this, arguments);
    },

    /**
     * 从dom中复制部分样式给编辑器以保证编辑器样式和格子样式的一致性
     * @param dom 要复制样式的dom
     */
    cssFrom: function (dom,isEditable) {
        if (!this.editComp) {
            return;
        }
        var $dom = $(dom);

        var $comp = this.editComp;

        //wei:这里不知道为什么要remove掉原先的class,导致控件开始自定义的样式填报时无效。
        $comp.addClass($dom.attr("class"));
        //$comp.removeClass().addClass($dom.attr("class"));
        // alex:复制$dom的部分style
        $.each(['fontFamily', 'fontVariant', 'fontStyle', 'fontWeight', 'fontSize',
            'paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight', 'backgroundColor'], function (idx, el) {
            $comp.css(el, $dom.css(el));
        });
        if(isEditable && $dom.context.style && $dom.context.style.color){
            $comp.css('color', $dom.context.style.color);
        }
        if(isEditable && $dom.attr('hasWatermark') && !$dom.attr('cv')){
            $comp.css('color', $dom.getwatermarkcolor());
        }
        if ((/transparent|rgba\(0, 0, 0, 0\)/).test($comp.css('backgroundColor'))) {
            $comp.css('backgroundColor', 'white')
        }
        if(isEditable){
            $comp.removeClass("cur-tr-bg");
        }
        if(contentPane.options['selectedColor'] && isEditable){
            $comp.css('backgroundColor', 'transparent')
        }
    },

    /**
     * 判断控件所在的格子是否被编辑过
     * @returns {boolean}  编辑过则返回true,否则返回false
     */
    isDirty: function () {
        return this.isWriteDataChanged();
    },

    /**
     * 让原值和新值进行比较,判断该控件是否进行了值的改动
     * @returns {boolean}  如果值改动了返回true,否则返回false
     */
    isWriteDataChanged: function () {
        return this.options.oldValue == null || !FR.equals(this.options.oldValue, this.getValue());
    },

    /**
     * 设置控件的值并保存原值以做比较
     * @param value 新值
     * @param shouldFireEvent 是否需要触发控件的编辑后等事件
     * @returns {*}
     */
    setValue4Write: function (value, shouldFireEvent) {
        this.options.oldValue = value;
        return this.setValue(value, shouldFireEvent);
    },

    /**
     * 开始编辑
     */
    startEditing: function () {
    },

    /**
     * 结束编辑
     */
    stopEditing: function () {
    },

    /**
     * 重置控件的值,用于填报联动
     */
    reset: function () {
        this.setValue("");
    }
});
$.shortcut("writeEditor", FR.WriteEditor);

/**
 * 给填报使用的控件增加FR.WriteEditor所具有的函数,类似于继承接口
 */
(function () {
    var writeEditor = [FR.EditCompBaseEditor, FR.MultiFileEditor];
    var ex_extend = function (target, superclass) {
        if (target.superclass != superclass.superclass) {
            throw new Error("different supper class");
        }
        var prototype = superclass.prototype;
        target.superclass = prototype;
        for (var name in prototype) {
            if (!target.prototype[name]) {
                target.prototype[name] = prototype[name];
            }
        }
    };
    for (var i = 0, len = writeEditor.length; i < len; i++) {
        ex_extend(writeEditor[i], FR.WriteEditor);
    }
}());

/**
 * @class FR.WritePane
 */
$.extend(FR.WritePane.prototype, /**@class FR.WritePane*/ function () {
    var P = {
        isLoadingPage: -1,
        selectMethod: 'editable', //可选值all, editable表示所有格子都可选中或仅editable格子才能使用
        selectedIndex: -1, // alex:当前选中的WLGP的序号
        gotoFirstPage: function () {
            this.curLGP.gotoFirstPage();
        },
        gotoPreviousPage: function () {
            this.curLGP.gotoPreviousPage();
        },
        gotoNextPage: function () {
            this.curLGP.gotoNextPage();
        },
        gotoLastPage: function () {
            this.curLGP.gotoLastPage();
        },
        /*
         * alex:初始化ContentPane
         */
        initContentPane: function () {
            FR.WritePane.superclass.initContentPane.apply(this, arguments);
            //alex:加载write.css
            FR.$defaultImport('/com/fr/write/web/css/write.css', 'css');
            if (this.options["writeCss"]) {
                $.each(this.options["writeCss"], function (i, item) {
                    FR.$import(item, 'css');
                });
            }
            var tabPane = this.$contentPane.data("TabPane");
            var self = this;
            if (tabPane) {//james:TabPane
                tabPane.on(FR.Events.TABCHANGESTART, function () {
                    if (self.curLGP) {
                        self.stopEditing();
                        if ($('div.verify-error-info:visible', FR.$view_container).length > 0) {
                            $('div.verify-error-info:visible', FR.$view_container).hide();
                        }
                    }
                });
                //james:给TabPane绑定tabchange事件
                tabPane.on(FR.Events.TABCHANGE, function (tabPane, tabIndex) {
                    self.selectedIndex = tabIndex;
                    self.fireEvent(FR.Events.TABCHANGE, tabPane, tabIndex);
                });
                //james:给当前的FormPane绑定tabchange事件,这个是真正的执行tabchange的内容
                this.on(FR.Events.TABCHANGE, function (tabPane, tabIndex) {
                    if (self.delay) {
                        return;
                    }

                    self.selectedIndex = tabIndex;
                    var lgp = self.lgps[tabIndex];
                    if (lgp.loaded === false) {
                        lgp.loadLGPPane();
                    } else {
                        // Carl:这个怎么能不变
                        self.curLGP = lgp;
                        self.curLGP._selectFirstTD();
                        self.curLGP.onfocus();
                        if (!lgp.frozenModified && $('.frozen-center', lgp.$container).length > 0) {
                            if (lgp.$sheet_container.parent().isVisible()) {
                                FR.layoutFrozen(lgp.$sheet_container, lgp.$sheet_container.offset().top);
                                lgp.frozenModified = true;
                            }
                        }
                    }

//                    self.selectedIndex = lgp.idx;
                    // 填报分页,把目标sheet的页码信息传递给writePane,fire(afterload)为了更新工具栏的页码
                    if (self.options["cutpage"] == 'v' || self.options["cutpage"] == 'w') {
                        self.currentPageIndex = lgp.currentPageIndex;
                        self.reportTotalPage = lgp.reportTotalPage;
                        self.fireEvent(FR.Events.AFTERLOAD);
                        self.afterLoad();
                    }
                });

                var tabs = tabPane.options.tabs;//james:获取tabs的个数
                this.lgps = [];
                for (var i = 0, count = tabs.length; i < count; i++) {
                    this.lgps[i] = new FR.WLGP({idx: i, $container: $(tabs[i].content), writePane: this, selectMethod: this.selectMethod});
                }
            } else {
                this.lgps = [new FR.WLGP({idx: 0, $container: this.$contentPane, writePane: this, selectMethod: this.selectMethod})];
            }

            if (this.options['selectedColor']) {
                var color = '.cur-tr-bg{background-color:' + this.options['selectedColor'] + '!important}';
                $('<style type="text/css">' + color + '</style>').appendTo('head');
            }

            // 初始化粘贴功能
            $("body").append("<div style='position:absolute;left:-1000px;top:-1000px;'><textarea id='cpTextArea' onkeyup='this.blur()'></textarea></div>");

            /**
             * 页面转向时提示,不支持opera
             */
            window.onbeforeunload = this.beforeUnloadCheck.createDelegate(this);

            // 防止backspace跳转.
            $(document)[(FR.Browser.r.gecko || FR.Browser.r.opera)
                ? 'keypress'
                : 'keydown'](function (e) {
                self.banBackSpace(e);
            });

        },

        banBackSpace: function (e) {
            if (e.keyCode === 8) {
                var t = e.target;
                t = t.type || t.getAttribute('type');
                if (t != "password" && t != "text" && t != "textarea") {
                    e.stopEvent();
                }
            }
        },

        /*
         * 开始加载ContentPane
         */
        loadContentPane: function (reloadOthers) {

            var tabPane = this.$contentPane.data("TabPane");
            if (tabPane) {
                tabPane.visible();
            }

            if (this.lgps == null || this.lgps.length === 0) {
                return;
            }

            // 是否需要重新加载当前sheet以外的sheet
            if (reloadOthers !== false) {
                $.each(this.lgps, function (idx, lgp) {
                    lgp.loaded = false;
                    //清除掉之前记录的移动行列格子缓存
                    lgp.lastRow = null;
                    lgp.lastCol = null;
                });
            }
            if (this.curLGP == null) {
//                this.curLGP = this.lgps[0];
//                this.selectedIndex = 0;
                // 如果页面还没开始加载 切换到第二个sheet 再点查询按钮加载页面 需要load第二个sheet
                if (this.selectedIndex > 0) {
                    this.curLGP = this.lgps[this.selectedIndex];
                } else {
                    this.curLGP = this.lgps[0];
                    this.selectedIndex = 0;
                }
            }
            this.delay = false;
            this.curLGP.loadLGPPane();
            //b:加载完成后,尝试
            if (this.$contentPane.data("TabPane")) {
                this.fireEvent(FR.Events.SCROLLCHANGE, this.$contentPane.data("TabPane"), 0);
            }
        },

        /**
         * carl:单sheet的reload  fec:reload后需要一开始select的格子
         * @param fec
         */
        reloadCurLGPPane: function (fec) {
            if (this.lgps == null || this.lgps.length === 0) {
                return;
            }
            if (this.curLGP == null) {
                return;
            }
            this.curLGP.loaded = false;
            if (fec) {
                this.curLGP.$fec = fec;
            }
            this.curLGP.loadLGPPane();
        },

        /**
         * 当前sheet重新计算
         */
        reCalCurLGPPane: function () {
            if (this.lgps == null || this.lgps.length === 0 || this.curLGP == null) {
                return;
            }
            var self = this;
            // 可能在控件编辑结束事件中执行 延时一下等待dirty状态
            setTimeout(function () {
                // 有没保存的数据的话要先保存下 这个是同步的
                if (self.curLGP.dirtyCell && self.curLGP.dirtyCell.length > 0) {
                    var ce = self.curLGP.dirtyCell[0];
                    self.writeDirtyAndRemoteCal(self.curLGP.idx, FR.id2ColumnRow(ce.id), ce);
                }

                FR.ajax({
                    url: FR.servletURL,
                    type: 'POST',
                    async: true,
                    data: {
                        op: "fr_write",
                        cmd: "refresh_w_data",
                        reportIndex: self.curLGP.idx,
                        sessionID: self.currentSessionID
                    },
                    complete: function (res, status) {
                        if (status == 'success') {
                            var ces = FR.jsonDecode(res.responseText);
                            if (ces.success) {
                                var value;
                                ces = ces.array;
                                $.each(ces, function (idx, item) {
                                    value = item.cv;
                                    if (typeof value == 'object') {
                                        if (value.date_milliseconds) {
                                            value = new Date(value.date_milliseconds);
                                        }
                                    }
                                    if (!FR.equals(self.curLGP.getCellValue(item.col, item.row), value)) {
                                        self.curLGP.setCellValue(item.col, item.row, value);
                                    }
                                });
                            }
                        }
                    }
                })
            }, 100);
        },

        /**
         * 更新所有sheet
         */
        refreshAllSheets: function () {
            var self = this;
            FR.ajax({
                url: FR.servletURL + '?op=fr_dialog&cmd=parameters_d&sessionID=' + this.currentSessionID + "&_random=" + (Math.random() * 10000),
                type: "POST",
                data: {
                    __parameters__: this.parameterEl ? this.parameterEl.collectionValue() : ""
                },
                complete: function () {
                    $.each(self.lgps, function (idx, lgp) {
                        lgp.loaded = false;
                    });
                    self.curLGP.loadLGPPane();
                }
            });
        },

        /**
         * 获取单元格的值
         * 获取第一个sheet的第二行第三列的值:
         *
         *     @example
         *     contentPane.getCellValue({reportIndex:0, columnIndex: 2, rowIndex: 1});
         *     contentPane.getCellValue(2, 1)
         *     contentPane.getCellValue(0, 2, 1)
         *
         * @param {json} o
         * {<br/>
         *     reportIndex:rpIdx,   // sheet序号<br/>
         *     columnIndex:colIdx,  // 格子所在的列序号<br/>
         *     rowIndex:rowIdx      // 格子所在的行序号<br/>
         * }
         * @returns {*}
         */
        getCellValue: function (o) {
            var config = {};
            // 兼容老的参数
            if (arguments.length === 2) {
                config.columnIndex = arguments[0];
                config.rowIndex = arguments[1];
                config.reportIndex = this.selectedIndex;
            } else if (arguments.length === 3) {
                config.reportIndex = arguments[0];
                config.columnIndex = arguments[1];
                config.rowIndex = arguments[2];
            } else {
                config = o;
            }
            if (this.lgps[config.reportIndex]) {
                return this.lgps[config.reportIndex].getCellValue(config.columnIndex, config.rowIndex);
            }
        },

        /**
         * 根据名字获取单个控件,如果有相同名字的控件,只取最后一个
         * @param name 控件的名字
         * @returns {FR.Widget} 指定名字的控件
         */
        getWidgetByName: function (name) {
            return this.curLGP.write.getWidgetByName(name);
        },

        /**
         * 根据单元格编号获取控件
         * @param cell  控件所在的单元格的编号
         * @returns {FR.Widget}   执行格子中的控件
         */
        getWidgetByCell: function (cell) {
            return this.curLGP.write.getWidgetByCell(cell);
        },

        /**
         * 根据名字获取控件
         * @param name  要获取的控件的名字
         * @returns {Array} 所有具有指定名字的控件组成的数组
         */
        getWidgetsByName: function (name) {
            return this.curLGP.write.getWidgetsByName(name);
        },

        /**
         * 给单元格赋值
         * 给第一个sheet的第二行第三列赋值为'aa':
         *
         *     @example
         *     contentPane.setCellValue(2, 1, "aa");
         *     contentPane.setCellValue({reportIndex:0, rowIndex:1, columnIndex:2, value:"aa"});
         *
         * @param {json} o
         * o {
         *     reportIndex:rpIdx, //sheet序号
         *     columnIndex:colIdx,//格子所在的列序号
         *     rowIndex:rowIdx,   //格子所在的行序号
         *     value:cv           //要给格子赋的值
         * }
         */
        setCellValue: function (o) {
            var config = {};
            //为了兼容以前的多参数写法
            if (arguments.length === 3) {
                config.columnIndex = arguments[0];
                config.rowIndex = arguments[1];
                config.value = arguments[2];
                config.reportIndex = this.selectedIndex;
            } else if (arguments.length === 4) {
                config.reportIndex = arguments[0];
                config.columnIndex = arguments[1];
                config.rowIndex = arguments[2];
                config.value = arguments[3];
            } else {
                config = o;
            }
            var lp = this.lgps[config.reportIndex];
            if (lp) {
                if (lp.loaded === false) {
                    lp.loadLGPPane(false);
                }
                lp.setCellValue(config.columnIndex, config.rowIndex, config.value);
                lp.fireCellValueChange(lp.getTDCell(config.columnIndex, config.rowIndex), config.value);
            }
        },

        /**
         * 停止编辑当前单元格
         */
        stopEditing: function () {
            if (this.curLGP) {
                this.curLGP.stopCellEditing();
            }
        },

        /**
         * 校验并提交修改数据,该函数在服务器端写死了调用
         *
         * 绑定成功失败事件可以用on动态绑定
         * 但是有时候客户并不引用我们的js这个时候就传入方法
         *
         * @param isAllSheet
         * @param submitButton
         * @param successFn
         * @param failFn
         * @returns {boolean}  提交成功返回true,否则返回false
         */
        verifyAndWriteReport: function (isAllSheet, submitButton, successFn, failFn) {
            if (this.fireEvent(FR.Events.BVW, this) === false) {
                return false;
            }

            //wei : 让提交按钮不可用
            if (submitButton) {
                submitButton.disable();
            }
            var o = {
                overlay_immediately: true,
                text: FR.i18nText("FR-Engine-Cal_Calculating") + "...."
            };
            FR.showLoadingDialog(o);
            var self = this;
            this.preventNoVerifier = true;
            var verify = function () {
                self._doVerify(
                    self.writeReport.createDelegate(self, [(isAllSheet ? null : self.selectedIndex), submitButton, successFn, failFn]),
                    function (resultJSON) {
                        self.popupError(resultJSON, submitButton);
                        submitButton && submitButton.enable();
                    },
                    isAllSheet ? null : self.selectedIndex, (arguments[1] ? arguments[1] : undefined));
            };
            // shoc:延迟10ms执行,防止大数据量填报时候浏览器卡死阻塞设置提交控件disable的执行,客户bug26782
            setTimeout(verify, 10);
        },

        /**
         * @Deprecated 名字太差,不再推荐使用
         * 使用请参见 {@link writeReportIgnoreVerify}
         */
        writeAndVerifyReport: function (isAllSheet) {
            this.writeReportIgnoreVerify(isAllSheet);
        },

        /**
         * 忽略校验出错信息,直接提交
         * 提交按钮勾选校验失败仍然提交执行的方法
         * 705前是只提交当前sheet 改为提交全部sheet 48285
         *
         * @param isAllSheet 是否提交全部sheet
         */
        writeReportIgnoreVerify: function (isAllSheet) {
            if (this.fireEvent(FR.Events.BVW, this) === false) {
                return false;
            }
            var self = this;
            var idx = isAllSheet ? null : this.selectedIndex;
            var successFn = this.writeReport.createDelegate(this, [idx]);
            this._doVerify(successFn, function (resultJSON) {
                successFn();
                self.popupError(resultJSON);
            }, idx);
        },

        // carl:后台计算
        // TODO
        writeDirtyAndRemoteCal: function (idx, location) {
            if (location == null) {
                return;
            }
            var fec;
            var data;
            var loads = [];
            for (var i = 0; i < this.lgps.length; i++) {
                if (this.lgps[i].loaded !== false) {
                    loads.push(i);
                }
            }
            if ($.isArray(location)) {
                fec = location[0];
                data = {
                    op: "fr_write",
                    cmd: "cal_write_cell",
                    editcells: location,
                    editReportIndex: idx,
                    sessionID: this.currentSessionID,
                    reportXML: this.generateReportXML(false),
                    loadidxs: loads
                };
            } else {
                fec = location;
                data = {
                    op: "fr_write",
                    cmd: "cal_write_cell",
                    editcol: location.col,
                    editrow: location.row,
                    editReportIndex: idx,
                    sessionID: this.currentSessionID,
                    reportXML: this.generateReportXML(false),
                    loadidxs: loads
                };
            }
            var o = {
                overlay_immediately: true,
                text: FR.i18nText("FR-Engine-Cal_Calculating") + "...."
            };
            FR.showLoadingDialog(o);

            var self = this;
            var fn = function (res, status) {
                if (status == 'success') {
                    var ces = FR.jsonDecode(res.responseText);
                    // 拿到后改所有的格子的值
                    if (ces.error) {
                        FR.hideLoadingDialog();
                        FR.Msg.alert(FR.i18nText("FR-Engine_Failed"), ces.error, function () {
                            self.reloadCurLGPPane(location)
                        });
                    } else if (ces.success) {
                        var value;
                        var pv;
                        var hy;
                        ces = ces.array;
                        $.each(ces, function (idx, item) {
                            value = item.cv;
                            pv = item.pv;
                            hy = item.hy;
                            if (typeof value == 'object') {
                                if (value.date_milliseconds) {
                                    value = new Date(value.date_milliseconds);
                                }
                            }
                            if (typeof pv == 'object') {
                                if (pv.date_milliseconds) {
                                    pv = new Date(value.date_milliseconds);
                                }
                            }
                            self.lgps[item.idx].setCellValue(item.col, item.row, value, pv, hy);
                        });
                    } else {
                        FR.hideLoadingDialog();
                        FR.Msg.alert(FR.i18nText("FR-Engine_Failed"), res.responseText, function () {
                            self.reloadCurLGPPane(fec)
                        });
                    }
                } else {
                    FR.hideLoadingDialog();
                    FR.Msg.alert(FR.i18nText("FR-Engine_Failed"), FR.i18nText("FR-Engine_Abnormal_Communication"), function () {
                        self.reloadCurLGPPane(fec)
                    });
                }
            };
            FR.ajax({
                url: FR.servletURL,
                type: 'POST',
                async: false,
                data: data,
                complete: (fn).createSequence(FR.hideLoadingDialog)
            });
        },

        /**
         * 填报入库
         * 填报入库第一个sheet,成功的话alert成功,失败就alert失败:
         *
         *     @example
         *     contentPane.writeReport(0, null, function(){alert("成功");}, function(){alert("失败");});
         *
         * @param reportIndex
         * @param submitButton
         * @param successFn
         * @param failFn
         * @return {boolean}
         */
        writeReport: function (reportIndex, submitButton, successFn, failFn) {
            if (this.fireEvent(FR.Events.BW, this) === false) {
                return false;
            }
            var self = this;
            var params = {op: "fr_write", cmd: "submit_w_report"};
            if (reportIndex != null) {
                params = $.extend(params, {reportIndex: reportIndex});
            }
            if (this.extraParas) {
                params = $.extend(params, this.extraParas);
            }
            doSave.call(this, {params: params, fn: function (res, status) {
                var submitInfo, builtinFail;
                var json_array = FR.jsonDecode(res.responseText);
                if (json_array.length > 0) {
                    $.each(json_array, function (idx, item) {
                        if (item.fr_submitinfo) {
                            submitInfo = item.fr_submitinfo;
                        }
                        if (item.builtinFail != null) {
                            builtinFail = item.builtinFail;
                        }
                    });
                }
                if (submitButton) {
                    // bug26782
                    setTimeout(function () {
                        submitButton.enable();
                    }, 10);
                }
                if (self.fireEvent(FR.Events.AVW, self, submitInfo) === false) {
                    return;
                }
                if (self.fireEvent(FR.Events.AW, submitInfo) === false) {
                    return;
                }
                var success = submitInfo.success;
                if (success !== true && success !== false) {
                    if (!self.preventNoWriter) {
                        // carl:这里表示没有填报属性设置,提示用户即可
                        FR.Msg.toast(FR.i18nText("FR-Engine_Report") + FR.i18nText("FR-Engine-Report-Write_Attributes_Msg"));
                    } else {
                        successFn && successFn();
                        delete self.preventNoWriter;
                    }
                } else if (success === true) {
                    //暂时只有设置自动暂存的时候才会在提交成功的时候清空暂存数据
                    if (self.isAutoStash()) {
                        self.clear(false);
                    }
                    FR.Msg.toast(FR.i18nText("FR-Engine_Successfully"));

                    self.fireEvent(FR.Events.WS);
                    if ($.isFunction(successFn)) {
                        successFn();
                    }
                } else if (success === false) {
                    if(submitInfo.failedcell){
                        self.popupError(submitInfo.failedcell);
                    }
                    FR.Msg.toast(builtinFail ? FR.i18nText("FR-Engine_Failed") : submitInfo.failinfo);
                    self.fireEvent(FR.Events.WF);
                    if ($.isFunction(failFn)) {
                        failFn();
                    }
                }
            }});
        },
        /*
         * fn是保存之后的callback
         */
        saveReport: function (fn, params) {
            doSave.call(this, {
                fn: fn || function (res) {
                    FR.Msg.toast(res.responseText);
                },
                params: params
            })
        },

        /**
         * 数据校验
         *
         * @param btn
         * @param reportIndex
         */
        verifyReport: function (btn, reportIndex) {
            var verifyButton = this.verifyButton = arguments[0];
            if (verifyButton) {
                verifyButton.disable();
            }
            var self = this;
            var $blankMsg = this._doVerify(function () {
                FR.Msg.toast(FR.i18nText("FR-Engine-Verify-Verify_Success"));
                verifyButton && verifyButton.enable();
            }, function (resultJSON) {
                self.popupError(resultJSON, verifyButton)
                verifyButton && verifyButton.enable();
            }, reportIndex);
        },

        validRegexWidget: function(widget, location, resultJSON, value, indexOfWidgets) {
            var errorMsg = widget.errorMsg || FR.i18nText("FR-Engine-Error_Input_Value");
            for (var indexOfPlugin = 0, lengthOfPlugin = FR.BaseEditor.PluginRegex.length; indexOfPlugin < lengthOfPlugin; indexOfPlugin++) {
                var obj = FR.BaseEditor.PluginRegex[indexOfPlugin];
                if(obj.text === widget.regex){
                    if(obj.regex(value)){
                        return true;
                    }else{
                        resultJSON.push({message: errorMsg, columnrows: [location], reportIndex: indexOfWidgets.id.split('-')[1]});
                        return false;
                    }
                }
            }
            if (typeof widget.regex == 'string') {
                var regex = new RegExp(widget.regex);
            }
            if (!regex.test(value)) {
                resultJSON.push({message: errorMsg, columnrows: [location], reportIndex: indexOfWidgets.id.split('-')[1]});
                return false;
            }
            return true;
        },

        //b:为了避免创建dom而用了这么个方法,和widget的isvalidate代码重复要考虑特殊控件的特殊属性,ugly
        //hiram 优化了一下实现
        validateWidgets: function (resultJSON) {
            var widgets = [];
            if (arguments[1] === true) {
                //wei:保存下curLGP,避免后面loadLGPPane后发生变化
                var currentLGP = this.curLGP;
                for (var i = 0; i < this.lgps.length; i++) {
                    //wei:想校验所有sheet,那么校验前必须先加载一次
                    if (this.lgps[i].loaded === false) {
                        //wei:因为bug2960改为ajax异步,但是多sheet加载时需要ajax同步,所以传递参数false表示是否异步
                        this.lgps[i].loadLGPPane(false);
                    }
                    var lgpWidgets = $('td[editor],td[widget]', this.lgps[i].$sheet_container);
                    $.each(lgpWidgets, function (idx, item) {
                        widgets = widgets.concat(item);
                    })
                }
                this.curLGP = currentLGP;
            } else {
                widgets = $('td[editor],td[widget]', this.curLGP.$sheet_container);
            }
            for (var i = 0, len = widgets.length; i < len; i++) {
                if ($(widgets[i]).hasClass("del")) {
                    continue;
                }
                var widget = FR.jsonDecode($(widgets[i]).attr('widget') || $(widgets[i]).attr('editor'));
                //bug86620如果控件不可用则不校验
                if (widget.disabled === true) {
                    continue;
                }
                var location = widget.location;
                var value = $(widgets[i]).attr('cv');
                if (!value || value == "null") {
                    value = "";
                } else {
                    if (value.startWith('"') && value.endWith('"')) {
                        value = value.substring(1, $(widgets[i]).attr('cv').length - 1);
                    }
                }
                if (widget.allowBlank === false && value === "") {
                    var errorMsg = widget.errorMsg || FR.i18nText("FR-Engine-Not_NULL");
                    resultJSON.push({message: errorMsg, columnrows: [location], reportIndex: widgets[i].id.split('-')[1]});
                    continue;
                } else if (widget.allowBlank !== false && value === "") {
                    continue;
                }
                if (widget.allowBlank !== false && value === "") {
                    continue;
                }
                if (widget.regex) {
                    if (!this.validRegexWidget(widget, location, resultJSON, value, widgets[i])){
                        continue;
                    }
                }
                if (widget.type === "number") {
                    var num = value, errorMsg = '', verify = true;
                    if (value != '' && isNaN(num)) {
                        var errorMsg = widget.errorMsg || FR.i18nText("FR-Engine-Err-The_value_must_be_number");
                        resultJSON.push({message: errorMsg, columnrows: [location], reportIndex: widgets[i].id.split('-')[1]});
                        continue;
                    }
                    num = isNaN(num) ? '' : num;
                    var numString = '' + num;
                    if (numString.indexOf(".") > 0) {
                        if (widget.allowDecimals === false) {
                            errorMsg = widget.errorMsg || FR.i18nText("FR-Engine-Err-The_Value_Must_Be_Integer");
                            resultJSON.push({message: errorMsg, columnrows: [location], reportIndex: widgets[i].id.split('-')[1]});
                            continue;
                        } else if (widget.allowDecimals !== false) {
                            // 判断小数位数 去掉负号
                            if (numString.startWith('-')) {
                                numString = numString.substring(1);
                            }
                            // shoc:科学计数法处理下
                            if (numString.indexOf('E') !== -1) {
                                var es = parseInt(numString.substring(numString.lastIndexOf('E') + 1, numString.length));
                                if (numString.indexOf('E') - 1 - numString.indexOf(".") <= widget.maxDecLength + es) {
                                    continue;
                                }
                            }
                            else {
                                if (numString.length - numString.indexOf(".") <= widget.maxDecLength + 1) {
                                    continue;
                                }
                            }
                            errorMsg = widget.errorMsg || FR.i18nText("FR-Engine-Decimal_Number_Out");
                            resultJSON.push({message: errorMsg, columnrows: [location], reportIndex: widgets[i].id.split('-')[1]});
                            continue;
                        }

                    }
                    if (widget.allowNegative === false && num < 0) {
                        errorMsg = widget.errorMsg || FR.i18nText("FR-Engine-Err-The_Value_Cannot_Be_Negative");
                        resultJSON.push({message: errorMsg, columnrows: [location], reportIndex: widgets[i].id.split('-')[1]});
                        continue;
                    }
                    if (widget.minValue != null && num < widget.minValue) {
                        errorMsg = widget.errorMsg || FR.i18nText("FR-Engine-Err-The_Number_Is_Less_Than_The_Minimum_Value") + widget.minValue;
                        resultJSON.push({message: errorMsg, columnrows: [location], reportIndex: widgets[i].id.split('-')[1]});
                        continue;
                    }
                    if (widget.maxValue != null && num > widget.maxValue) {
                        errorMsg = widget.errorMsg || FR.i18nText("FR-Engine-Err-The_Number_Is_Larger_Than_The_Maximum_Value") + widget.maxValue;
                        resultJSON.push({message: errorMsg, columnrows: [location], reportIndex: widgets[i].id.split('-')[1]});
                        continue;
                    }
                }
            }
        },



        _doVerify: function (successFn, failureFn, reportIndex) {//私有方法
            // 要先stop editing
            this.stopEditing();
            // shoc:verify前先移除全部  bug28182
            this.removeError(reportIndex);

            var resultJSON = [];

            var self = this;
            var params = {op: "fr_write", cmd: "write_verify"};
            // richer:是否需要调用Widget的invalidate()方法来进行校验?
            // james:先校验整个报表中是不是有不允许为空,但没有cv值的格子
            if (reportIndex != null) {
                this.validateWidgets(resultJSON);
                params = $.extend(params, {reportIndex: reportIndex});
            } else {
                this.validateWidgets(resultJSON, true);
            }

            //TODOJ 这里要经过一个verify过程,没有校验也要经过,不是很好,可是不知道怎么判断需要使用数据校验判断,想到了再加上
            doSave.call(this, {params: params, fn: function (res, status) {
                var verifyInfo = {};
                if (status == 'success') {
                    var json_array = FR.jsonDecode(res.responseText);
                    if (json_array.length > 0) {
                        $.each(json_array, function (idx, item) {
                            // 下面这个push的reportIndex全都是当前sheet的 不对 放在后台添加
                            //item.reportIndex = self.curLGP.idx;
                            if (item.fr_verifyinfo) {
                                verifyInfo = item.fr_verifyinfo;
                            } else {
                                resultJSON.push(item);
                            }
                        });
                    }
                }
                //如果填报属性里没有设置校验而前端控件校验失败 这时候应该返回失败
                if (resultJSON.length > 0) {
                    verifyInfo.success = false;
                }
                if (self.fireEvent(FR.Events.AV, verifyInfo) === false) {
                    if (self.verifyButton) {
                        self.verifyButton.enable();
                    }
                    return;
                }
                if (resultJSON.length > 0) {
                    $.isFunction(failureFn) && failureFn(resultJSON);
                } else {
                    if (verifyInfo.success === true || self.preventNoVerifier === true) {
                        $('div.verify-error-container', FR.$view_container).remove();
                        $('div.verify-error-number').remove();
                        $.isFunction(successFn) && successFn();
                    } else {
                        // 没有设置校验属性 或者 找不到自定义类的情况
                        // 填报时候带的校验不显示这个东西 只有单纯的数据校验才显示
                        FR.Msg.toast(verifyInfo.info);
                        self.verifyButton && self.verifyButton.enable();
                    }
                }
                delete self.preventNoVerifier;
            }});
        },
        /**
         * flash打印
         */
        flashPrint: function () {
            this.saveReport(FR.doFlashPrint.createCallback(this.currentSessionID));
        },

        /**
         * applet打印
         */
        appletPrint: function () {
            this.saveReport(FR.doAppletPrint.createCallback(this.currentSessionID));
        },

        /**
         * 导出pdf
         * @param extype
         */
        exportReportToPDF: function (extype) {
            if (this.fireEvent(FR.Events.BTOPDF) === false) {
                return;
            }
            var self = this;
            this.saveReport(function () {
                window.location = FR.servletURL + "?op=export&sessionID=" + self.currentSessionID + "&format=pdf&fr_embedded=true&extype=" + extype;
                FR.progressBar(self.currentSessionID,"pdf");
            });
            this.fireEvent(FR.Events.ATOPDF);
        },

        /**
         * 导出Excel
         *
         *     @example
         *     contentPane.exportReportToExcel('simple');//原样导出excel
         *     contentPane.exportReportToExcel('page', [1]);//分页导出excel,并且只导出第二个sheet
         *
         * @param extype 导出方式
         * @param sheets 导出的sheet序号数组
         */
        exportReportToExcel: function (extype, sheets) {
            if (this.fireEvent(FR.Events.BTOEXCEL) === false) {
                return;
            }
            var sheetStr = "";
            if (sheets != null && $.isArray(sheets)) {
                sheetStr += "&sheets=[";
                for (var i=0; i<sheets.length; i++) {
                    sheetStr += sheets[i] + "";
                    if (i < sheets.length - 1) {
                        sheetStr += ",";
                    }
                }
                sheetStr += "]";
            }
            var self = this;
            this.saveReport(function () {
                var flag = extype.indexOf("_");
                if (flag != -1) {
                    var extypeNew = extype.substring(0, flag);
                    window.location = FR.servletURL + "?op=export&sessionID=" + self.currentSessionID + "&format=excel&extype=" + extypeNew + "&isExcel2003=" + true + sheetStr;
                } else {
                    window.location = FR.servletURL + "?op=export&sessionID=" + self.currentSessionID + "&format=excel&extype=" + extype + sheetStr;
                }
                FR.progressBar(self.currentSessionID,"excel");
                self.fireEvent(FR.Events.ATOEXCEL);
            });
        },

        /**
         * 导出word
         */
        exportReportToWord: function () {
            if (this.fireEvent(FR.Events.BTOWORD) === false) {
                return;
            }
            var self = this;
            this.saveReport(function () {
                window.location = FR.servletURL + "?op=export&sessionID=" + self.currentSessionID + "&format=word";
                FR.progressBar(self.currentSessionID,"word");
                self.fireEvent(FR.Events.ATOWORD);
            });

        },

        /**
         * 导出图片
         *
         *     @example
         *     contentPane.exportReportToImage('png'); //导出png类型的图片
         *
         * @param extype
         */
        exportReportToImage: function (extype) {
            if (this.fireEvent(FR.Events.BTOIMAGE) === false) {
                return;
            }
            var self = this;
            this.saveReport(function () {
                window.location = FR.servletURL + "?op=export&sessionID=" + self.currentSessionID + "&format=image&extype=" + extype;
                self.fireEvent(FR.Events.ATOIMAGE);
            });
        },

        /**
         * 导出html
         */
        exportReportToHtml: function () {
            if (this.fireEvent(FR.Events.BTOHTML) === false) {
                return;
            }
            var self = this;
            this.saveReport(function () {
                window.location = FR.servletURL + "?op=export&sessionID=" + self.currentSessionID + "&format=html";
                self.fireEvent(FR.Events.ATOHTML);
            });
        },

        /**
         * 导出离线填报报表
         */
        exportReportToWriteOfflineHtml: function () {
            var self = this;
            if(FR.Browser.isIE9Later()){
                FR.Msg.alert(FR.i18nText("FR-Designer_Tooltips"),FR.i18nText("FR-Engine_Offline_Html_Error"),function(){self.exportReportToOffineHtml();});
            }else{
                self.exportReportToOffineHtml();
            }
        },

        /**
         * 将报表导出为离线html
         */
        exportReportToOffineHtml:function(){
            if (this.fireEvent(FR.Events.BTOHTML) === false) {
                return;
            }
            var self = this;
            this.saveReport(function () {
                window.location = FR.servletURL + "?op=export&sessionID=" + self.currentSessionID + "&format=write_html";
                self.fireEvent(FR.Events.ATOHTML);
            });
        },

        /**
         * 服务器端打印
         */
        printReportServer: function () {
            if (this.fireEvent(FR.Events.BSEVERPRINT) === false) {
                return;
            }
            this.saveReport(FR.showIframeDialog.createCallback({
                title: FR.i18nText("FR-Engine-ReportServerP_Print[Server]"),
                width: 540,
                height: 380,
                url: FR.servletURL + "?op=fr_dialog&cmd=read_print_server_dialog&sessionID=" + this.currentSessionID + "&pn=0"
            }));
            this.fireEvent(FR.Events.ASERVERPRINT);
        },

        /**
         * 设置打印偏移
         */
        SetPrinterOffset: function () {
            FR.showIframeDialog({
                title: FR.i18nText("FR-Engine-Print_Set_Printer_Offset"),
                width: 420,
                height: 300,
                url: FR.servletURL + "?op=printer_offset&cmd=pt_open&sessionID=" + this.currentSessionID
            });
        },

        /**
         * 发送邮件
         */
        emailReport: function () {
            if (this.fireEvent(FR.Events.BEMAIL) === false) {
                return;
            }
            var self = this;
            this.saveReport(FR.showEmailDialog.createCallback({
                sessionID: this.currentSessionID,
                onFinish: function () {
                    self.fireEvent(FR.Events.AEMAIL);
                }
            }));
        },

        downloadByAddress: function (attachUrl) {
            FR.ajax({
                url: attachUrl,
                complete: function (res, status) {
                    if (status == 'success') {
                        var u = FR.jsonDecode(res.responseText);
                        if (u != null && u.url) {
                            window.open(u.url);
                        }
                    }
                }
            });
        },


        /**
         * @private
         * @param saveData
         * @returns {string}
         */
        generateReportXML: function (saveData) {
            var xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>";
            xml += "<WorkBook>";
            xml += ("<Version>6.5</Version>");//marks:

            //alex:iterate all reports
            var centerPanelCount = this.lgps.length;
            for (var i = 0; i < centerPanelCount; i++) {
                var $table = this.lgps[i].$table;
                if ($table == null || $table.length === 0) {
                    continue;
                }

                xml += "<Report class=\"com.fr.report.WorkSheet\" name=\"" + i + "\">";
                xml += "<CellElementList>";

                $.each(this.lgps[i].dirtyCell, function (idx, tdCell) {
                    var $tdCell = $(tdCell);
                    //alex:取出需要edit的内容
                    if ($tdCell.attr('cv') != null) {//marks:是否为空
                        var columnRow = FR.id2ColumnRow($tdCell.attr("id"))

                        xml += "<C c=\"" + columnRow.col + "\" r=\""
                            + columnRow.row + "\">";
                        xml += writeCellValue(tdCell);
                        xml += "</C>";
                    }
                });

                this.lgps[i].dirtyCell = [];

                if (saveData) {
                    // alex:查找cv不为null且status是D(isDirty)的TD,//marks:在ie下cv=0返回为false,所以cv是否为空调整到下面处理
                    $('td.dirty', $table).each(function (idx, tdCell) {
                        //marks:去cv值,看他是否为 null
                        var $tdCell = $(tdCell);

                        $tdCell.removeClass('dirty');
                    });
                }

                xml += "</CellElementList>";
                xml += "</Report>";
            }

            xml += "</WorkBook>";

            return xml;
            /*
             * alex:做一下小结,想不起当初为什么要替换+为%2B了
             * 但BUG0003106显示,如果公式中有+,做了%2B替换后,在后台原来的10+20就变成10%2B20了,就无法解析这个公式了
             */
//            return xml.replace(/\+/g, "%2B");   //TODO alex:想不起来当初为什么要做替换了
            //TODOJ james:是不是因为公式中有+,只是猜测……
        },

        // alex:frozen
        frozen: function (column, row) {
            this.curLGP.frozen(column, row);
        },

        /**
         * carl:离开页面时,假如有dirty数据,提示用户是否离开
         *
         * @returns {string}
         */
        beforeUnloadCheck: function () {
            this.stopEditing();
            if (this.isDirtyPage()) {
                if (this.options.unloadCheck !== false) {
                    return FR.i18nText("FR-Engine-Unload_Check_Msg") + "!";
                }
            }
        },

        /**
         * 判断是否有未提交数据
         * @returns {boolean}
         */
        isDirtyPage: function () {
            var centerPanelCount = this.lgps.length;
            for (var i = 0; i < centerPanelCount; i++) {
                var $table = this.lgps[i].$table;
                if ($table == null || $table.length === 0) {
                    continue;
                }
                if ($('td.dirty', $table).length > 0) {
                    return true;
                }
            }
            return false;
        },

        /**
         * excel导入
         */
        importExcel: function () {
            FR.showUploadDialog($.extend({
                title: FR.i18nText("Import-Excel_Import"),
                autoUpload: true
            }, this.importExcelOptions()));
            if(this.isAutoStash()){
                this.stash();
            }
        },

        /**
         * 初始化excel导入按钮
         * 自己创建一个按钮并把他作为excel导入按钮:
         *
         *     @example
         *     var btn = new FR.Button({text:'excel导入'});
         *     contentPane.initExcelButton(btn);
         *
         * @param button
         */
        initExcelButton: function (button) {
            //wei : 为了点击按钮就能弹出文件选择框,在按钮的位置放置了一个透明的文件上传控件。
            var importExcelButton = $(button.$table||button.$btndiv);
            importExcelButton.one("mouseover", function () {
                if ($("#importexcelform").length > 0) {
                    var $uploadForm = $("#importexcelform");
                    var input = $("input", $uploadForm);
                } else {
                    var $uploadForm = $('<form enctype="multipart/form-data" id="importexcelform"></form>').appendTo("body");
                    var input = $('<input type="file" name="file" style="width:86px; height:23px; cursor : pointer" size="2"/>').appendTo($uploadForm);
                }
                input.mouseover(
                    function () {
                        importExcelButton.mouseover();
                    }).mouseout(
                    function () {
                        importExcelButton.mouseout();
                    }).mousedown(
                    function () {
                        importExcelButton.mousedown();
                    }).mouseup(
                    function () {
                        importExcelButton.mouseup();
                    }).change(function () {
                    if (!button.isEnabled()) {
                        return;
                    }
                    _g().importExcelData()
                }).click(function (e) {
                    if (!button.isEnabled()) {
                        e.stopEvent();
                    }
                    if (contentPane.delay) {
                        e.stopEvent();
                    }
                    //neil:多次导入同一个excel值不变的bug 21287
                    this.value = "";
                });
                input.css({top: importExcelButton.offset().top,
                    left: importExcelButton.offset().left,
                    position: 'absolute',
                    'z-index': 9999,
                    'opacity': 0
                });
            });
        },
        importExcelOptions: function () {
            var self = this;
            return {
                url: FR.servletURL + "?sessionID=" + this.currentSessionID
                + "&op=fr_write&cmd=imp_w_excel_data",
                callback: function (res, status) {
                    if (status == 'success') {
                        var str = res.responseText;
                        if ("success" == str) {
                            this.loadContentPane();
                            if (FR.Browser.isIE()) {
                                //neil:为什么要这么蛋疼呢, 因为file这货在ie里面是readonly的, 不能随意改变值, replace掉
                                var $uploadForm = $("#importexcelform");
                                var input = $("input", $uploadForm);
                                input.replaceWith(input.clone(true));
                            }
                        } else if ("wrong" == str) {
                            FR.Msg.toast(FR.i18nText("FR-Engine-Import_Failed"));
                        } else if (str && str.indexOf("Error:") > -1) {
                            FR.Msg.toast(str);
                        } else if ("typewrong" == str) {
                            FR.Msg.toast(FR.i18nText("FR-Engine-Should_Select_An_Excel_File"));
                        }
                    } else {
                        FR.Msg.toast(FR.i18nText("FR-Engine-Send_Failed"));
                    }
                }.createDelegate(this),
                beforeAction: function () {
                    self.fireEvent(FR.Events.BIMEXCEL);
                },
                afterAction: function () {
                    self.fireEvent(FR.Events.AIMEXCEL);
                }
            };

        },
        // carl: op=write import excel data
        importExcelData: function () {
            FR.autoSubmit(this.importExcelOptions(), $("#importexcelform"));
        },

        // Carl: ctrl + v 复制数据
        pasteCells: function () {
            var lastSelectedTDCell = this.curLGP.currentTDCell;
            if (lastSelectedTDCell == null) {
                return;
            }

            var location = FR.id2Location(lastSelectedTDCell.id);
            if (location == null) {
                return;
            }

            var value = $("#cpTextArea").val();
            if (value == null || value == '') {
                return;
            }

            this.stopEditing();
            // alex:在处理#5346时,在chrome里面测试,发现从Excel里面拷贝过来的,前后都加一个回车符,如果不trim掉,Paste就会错位,往下移一行
//            var rows = $.trim(value).split("\n");
            // bug42177 复制的格子中前面带有空白格 trim了就没了 用chrome试了下
            // 当excel格式是设置的数字格式 后面可能会多一个换行符
            if (value.startWith('\n')) {
                value = value.substring(1, value.length);
            }
            if (value.endWith('\n')) {
                value = value.substring(0, value.length - 1);
            }
            /*
             * wei : 像google docs里的电子表格一样处理复制过来的excel数据
             * 如果是一个格子中有换行的数据,比如(a\nb)复制过来的到的value值会被加上引号("a\nb"),所以碰到被引号引起来的
             * 数据全当做在一个格子中处理;这样有一个缺陷:上下2个格子内容分别为'"a'和'b"'时,复制过去,会在一个格子里,并且没有引号
             * 但因为情况较少,折中做法,不作考虑
             */
            var flag = false, rows = [], start = 0;
            for (var i = 0; i < value.length; i++) {
                var ch = value.charAt(i);
                if (ch == '"') {
                    flag = !flag;
                } else if (ch == '\n' && !flag) {
                    rows.push(value.substring(start, i).replaceAll('""', '\n\r').replaceAll('"', '').replaceAll('\n\r', '"'));
                    start = i + 1;
                }
            }
            if (start < value.length) {
                rows.push(value.substring(start, i).replaceAll('""', '\n\r').replaceAll('"', '').replaceAll('\n\r', '"'));
            }

            var needChangeValue = function (cell, cev, editorO) {
                return cell != null &&
                    cell.attr("editor") != null
                    && cev != null
                    && cev.length > 0
                    && !editorO.disabled
                    && editorO.editable !== false
                    && editorO.directEdit !== false;
            };
            var firstCell = this.curLGP._get$TDCell(location.col, location.row);
            var firstWidget = contentPane.getWidgetByCell(FR.jsonDecode(firstCell.attr("editor")).location);
            var firstOri = firstWidget.getValue();
            for (var i = 0; i < rows.length; i++) {
                var cols = rows[i].split("\t");
                for (var j = 0; j < cols.length; j++) {
                    var cell = this.curLGP._get$TDCell(location.col + j, location.row + i);
                    //wei : 如果控件的属性disabled为true或者directEdit为false,那么Ctrl+V操作不应该改变其值。
                    var editorO = FR.jsonDecode(cell.attr("editor"));
                    var widget = contentPane.getWidgetByCell(editorO.location);
                    var cev = cols[j];
                    if (needChangeValue(cell, cev, editorO)) {
                        //bug86534,复制粘贴的时候校验需要select到当前赋值的格子
                        if (cell.length > 0) {
                            this.curLGP.selectTDCell(cell[0]);
                        }
                        // TODO carl:想在这儿弄校验,但似乎逻辑上怎么搞都不妥当,暂时不做,跟导入excel数据一样,让用户最后提交再校验好了。~_~
                        if (typeof cev == "string" && cev.startWith("=")) {
                            this.curLGP.fireCellValueChange(cell, null, cev, false);
                            this.curLGP.displayTDCell(cell, "");
                        } else {
                            if (widget && widget.getType() === 'number') {
                                // 如果是数字控件,则将复制的值转化成数字
                                // 考虑带千位符逗号的情况,去掉
                                if (cev) {
                                    cev = $.trim(cev);
                                    cev = cev.replaceAll(",", "");
                                }
                                // parseFloat会把"4.00"变成4  "4.0400"变成4.04
                                if (cev.indexOf('.') !== -1) {
                                    cev = cev.replace(/[0]+$/, '');
                                    if (cev.endWith('.')) {
                                        cev = cev.substring(0, cev.length - 1);
                                    }
                                } else if (cev.match(/^[0]+$/)) {
                                    cev = '0';
                                } else {
                                    cev = cev.replace(/^[0]+/, '');
                                }
                                var ori = cev;
                                cev = parseFloat(cev, 10);
                                // 粘贴10%、22sdf 这种数据,清除掉,前后有空格的保留
                                // ie9之前的版本不支持string的trim方法
                                if (cev && cev.toString() != $.trim(ori)) {
                                    cev = null;
                                }
                                if (isNaN(cev)) {
                                    cev = null;
                                }
                            }
                            this.curLGP.fireCellValueChange(cell, cev, null, false);
                            this.curLGP.displayTDCell(cell, cev);
                            // 客户bug35401 粘贴触发控件的编辑后事件
                            widget.fireEvent(FR.Events.AFTEREDIT);
                            widget.fireEvent(FR.Events.STOPEDIT);
                        }
                    }
                }
            }
            this.curLGP.calCurrentPage();
            if(this.isAutoStash()){
                this.stash();
            }
            if (rows.length === 1) {
                cols = rows[0].split("\t");
                if (cols.length === 1) {
                    if (this.curLGP.cellEditing == null) {
                        this.curLGP.editTDCell(null);
                        // ctrl+v第一个控件进入编辑状态 editTDCell里会设置控件oldValue、
                        // 正常编辑的话oldValue设置为编辑前的值 而粘贴的话已经是编辑过的值
                        firstWidget.options.oldValue = firstOri;
                    }
                }
            }
        },

        fireCurrentWidgetEvent: function (event) {
            var lastSelectedTDCell = this.curLGP.currentTDCell;
            if (lastSelectedTDCell == null) {
                return;
            }
            var location = FR.id2Location(lastSelectedTDCell.id);
            if (location == null) {
                return;
            }
            var cell = this.curLGP._get$TDCell(location.col, location.row);
            var editor = cell.attr("editor") || cell.attr("widget");//这边加一下直接显示控件的情况
            var editorO = FR.jsonDecode(editor);
            var widget = contentPane.getWidgetByCell(editorO.location);
            widget.fireEvent(event);
        },

        /**
         *  删除记录
         */
        deleteRows: function () {
            this.deleteReportRC.apply(this, arguments);
        },

        /**
         * 增加记录
         */
        appendRows: function () {
            this.appendReportRC.apply(this, arguments);
        },

        /**
         * 提供个接口实现单击就能进入编辑
         * contentPane.setEditOnClick(true);
         */
        setEditOnClick: function (editOnClick) {
            this.editOnClick = editOnClick;
        },

        isAutoStash:function(){
            return this.options.isAutoStash;
        },

        /**
         * 提供个接口实现按键切换格子立即进入编辑
         * contentPane.setEditOnMove(true);
         * @param editOnMove
         */
        setEditOnMove: function (editOnMove) {
            this.editOnMove = editOnMove;
        },

        /**
         * 编辑结束事件是否需要控件值改变才触发
         * @param fireOnChange
         */
        setFireStopEditOnChange: function (fireOnChange) {
            this.fireStopEditOnChange = fireOnChange;
        },

        setVerifyWidth: function(width) {
            this.verifyWidth = width;
        },

        //hiram : 用来同步前端与后台的数据,用于局部刷新
        refreshData: function () {
            var self = this;
            doSave.call(this, {
                params: {
                    op: "fr_write",
                    cmd: "read_w_content",
                    startRow: $("tr[tridx]:first", _g().options.renderEl).attr("tridx"),
                    endRow: $("tr[tridx]:last", _g().options.renderEl).attr("tridx"),
                    reportIndex: arguments[0],
                    __cutpage__: self.options.cutpage,
                    pn: self.currentPageIndex
                },
                fn: function (res, status) {
                    var $html = $(res.responseText);
                    var $tds = $("td[id]", $html);
                    this._refreshData($tds);
                }.createDelegate(this)
            })
        },
        _refreshData: function ($tds) {
            var $tds2 = $('td[id]', _g().options.renderEl);
            //    alert($tds2.length+"   "+$tds.length);
            $tds2.each(function (index, td) {
                var $td = $(td);
                if (!$td.attr("widget")) {
                    if ($td.attr("editor") && FR.jsonDecode($td.attr("editor")).type == 'multifile') {
                        return;
                    }
                    td.style.backgroundColor = $tds[index].style.backgroundColor;
                    if (td.innerHTML != $tds[index].innerHTML) {
                        td.innerHTML = $tds[index].innerHTML;
                    }
                    $td.attr("class", $($tds[index]).attr("class"));
                    if ($td.attr("cv") != $($tds[index]).attr("cv")) {
                        $td.attr("cv", $td.attr("cv"));
                    }
                }
            });
        },

        removeError: function (reportIndex) {
            var tabPane = this.$contentPane.data('TabPane');
            if (reportIndex == null || reportIndex == undefined) {
                $(".verify-error-img").remove();
                $(".verify-error-info").remove();
                if (tabPane) {
                    for (var i = 0; i < tabPane.tabBtns.length; i++) {
                        tabPane.tabBtns[i].setValidState(true);
                    }
                }
            } else {
                $(".verify-error-img", contentPane.lgps[reportIndex].$table).remove();
                $(".verify-error-info", contentPane.lgps[reportIndex].$table).remove();
                if (tabPane) {
                    tabPane.tabBtns[reportIndex].setValidState(true);
                }
            }
        },

        popupError: function (json_array) {
            if (json_array == null || !(FR.isArray(json_array))) {
                return '';
            }
            $('div.verify-error-container', FR.$view_container).remove();
            var $divContainer = $('<div/>').addClass('verify-error-container');
            var $errorMsgDiv = $('<div/>').addClass('verify-error-messages').appendTo($divContainer);
            var $tableWrapper = $('<div/>').addClass('verify-table-wrapper').appendTo($errorMsgDiv);
            var $table = $("<table cellspacing='0' cellpadding='0'>").addClass('verify-table').css('width', 200).appendTo($tableWrapper);
            var $tbody = $("<tbody>").appendTo($table);
            $divContainer.append($('<s/>').addClass('verify-error-s').append($('<i/>').addClass('verify-error-i')));
            var error_tabs = [];
            var tabPane = this.$contentPane.data('TabPane');
            if(!FR.isEmpty(tabPane)){
                this.currentTabIndex = tabPane.getSelectedIndex();
            }
            $.each(json_array, function (idx, item) {
                //wei:记录下有错tab的下标
                if (item.reportIndex != error_tabs[error_tabs.length - 1]) {
                    error_tabs.push(item.reportIndex);
                }
                var position = '';

                function makeErrorMsg(index) {
                    var iitem = json_array[index];
                    $.each(iitem.columnrows, function (idx, item2) {
                        position += item2 + ' ';
                        var $errorCell = _g().lgps[parseInt(item.reportIndex)]._get$TDCell(item2);
                        // 设置自动调整或者冻结,格子的结构与正常的不同
                        var $errorImgHolder = $(".fx", $errorCell).length === 0 ? $errorCell : $("td", $(".fx", $errorCell));
                        if(_g().lgps[parseInt(item.reportIndex)].write.lgp.isEditableWidget($errorCell.get(0))){
                            var $div4Hide = $('input',$("div", $errorImgHolder));
                            var offsetHeight = $errorImgHolder.height()-16+'px';
                            var offsetWidth = -6+'px';
                            if($div4Hide){
                                $div4Hide.css('background',"transparent url('"+ FR.servletURL + "?op=resource&resource=/com/fr/web/images/newwarning.png') no-repeat scroll "+ offsetWidth+ ' '+ offsetHeight);
                                $errorImgHolder.addClass('errorCellFlag');
                            }
                        }else if (($('.verify-error-img', $errorCell).length === 0)) {
                            var $errorMsgImg = $('<img border="0"/>').addClass('verify-error-img')
                                .appendTo($errorImgHolder).attr('title', item.message)
                                .attr('src', FR.servletURL + '?op=resource&resource=/com/fr/web/images/warning.png');
                        }
                    });
                }

                if (tabPane > 0) {
                    tabPane.tabBtns[parseInt(item.reportIndex)].setValidState(false);
                }
                if (tabPane != null ) {
                    tabPane.selectTabAt(parseInt(item.reportIndex));
                }

                makeErrorMsg(idx);
                // 如果出错的格子都没有在当前页,那么点击的时候要翻页
                var targetPage = contentPane.currentPageIndex;
                if (item.pages) {
                    if ($.inArray(contentPane.currentPageIndex, item.pages) === -1) {
                        targetPage = item.pages[0];
                    }
                }
                var $td = $('<td/>').css('cursor', 'pointer').text(item.message).hover(
                    function () {
                        $(this).addClass("verify-item-over");
                    },
                    function () {
                        $(this).removeClass("verify-item-over");
                    }).attr('title', 'Sheet' + (parseInt(item.reportIndex) + 1) + '-' + position + ':' + item.message)
                    .attr('id', item.columnrows.toString() + '-' + item.reportIndex)
                    .addClass('verify-item-idx' + item.reportIndex)
                    .click(function () {
                        if (targetPage != contentPane.currentPageIndex) {
                            contentPane.gotoPage(targetPage, false);
                            for (var i = 0; i < json_array.length; i++) {
                                makeErrorMsg(i);
                            }
                        }
                        var columnrows = item.columnrows;
                        if (this.idx == undefined || this.idx >= columnrows.length) {
                            this.idx = 0;
                        }
                        var tdCell = _g().lgps[parseInt(item.reportIndex)]._get$TDCell(columnrows[this.idx]);
                        if ($('div.verify-error-info', FR.$view_container).length > 0) {
                            $('div.verify-error-info', FR.$view_container).remove();
                        }
                        if (tabPane != null) {
                            tabPane.selectTabAt(parseInt(item.reportIndex));
                        }
                        // 隐藏列,不给数据校验提示
                        while(this.idx < columnrows.length ){
                            tdCell = _g().lgps[parseInt(item.reportIndex)]._get$TDCell(item.columnrows[this.idx]);
                            if (tdCell.css('display') != 'none') {
                                break;
                            } else {
                                this.idx++;
                            }
                        }
                        if(this.idx >= columnrows.length){
                            return;
                        }
                        var errorInfo = $('<div/>').addClass('verify-error-info').html(item.message).appendTo(FR.$view_container);
                        errorInfo.css({top: tdCell.offset().top - 10, left: tdCell.offset().left + tdCell.width() + 4});
                        _g().lgps[parseInt(item.reportIndex)].selectTDCell(tdCell[0]);
                    });
                $tbody.append($("<tr" + (idx % 2 === 0 ? " class='verify-row-alt'" : "") + "></tr>").append($td));
            });
            //bug:78752,切换到当前sheet
            if (tabPane != null && !FR.isEmpty(this.currentTabIndex)) {
                tabPane.selectTabAt(parseInt(this.currentTabIndex));
            }

            //Sean: 时间复杂度O(1)
            if (tabPane) {
                for (var i = 0; i < tabPane.tabBtns.length; i++) {
                    if (error_tabs.length > 0 && parseInt(error_tabs[0]) === i) {
                        tabPane.tabBtns[i].setValidState(false);
                        error_tabs.shift(0);
                    } else {
                        tabPane.tabBtns[i].setValidState(true);
                    }
                }
            }
            if (arguments[1]) {
                var button = arguments[1];
                var buttonElement = $('button', button.$table || button.$btndiv);
                if (buttonElement.hasClass('x-emb-verify')) {
                    buttonElement.text('');
                    var verifyDiv = $('<div style="display:inline;">' + FR.i18nText("Verify-Data_Verify") + '</div>');
                    var errorNumDiv = $('<div/>').text(json_array.length).addClass('verify-error-number');
                    buttonElement.append(verifyDiv).append(errorNumDiv);
                }
            }
            var collapseDiv = $('<div/>').addClass('verify-collapse').appendTo($errorMsgDiv)
                .click(
                    function () {
                        $(this).addClass("verify-collapse-over")
                    },
                    function () {
                        if ($('div.verify-error-container:visible', FR.$view_container).length > 0) {
                            $('div.verify-error-container:visible', FR.$view_container).animate({
                                height: 'toggle'
                            }, 'fast');
                        }
                    }).attr('title', FR.i18nText("FR-Engine-Click_To_Shrink_Panel"));
            collapseDiv.hover(
                function () {
                    $(this).addClass("verify-collapse-over")
                },
                function () {
                    $(this).removeClass("verify-collapse-over");
                });
            if (!FR.$view_container) {
                FR.$view_container = $("<div class='view-container'/>").appendTo('body');
            }
            if (button) {
                $divContainer.css('left', (button.element.offset().left - 40 < 0) ? 0 : button.element.offset().left - 40);
            }
            FR.$view_container.append($divContainer);

            if (FR.Browser.isIE7Before() && $tableWrapper[0].scrollHeight > 250) {
                $tableWrapper.height(250);
            }
            if (this.verifyWidth) {
                var w = this.verifyWidth;
                $divContainer.width(w);
                $table.width(w);
                collapseDiv.width(w);
            }
        },

        /**
         * 插入行按钮使用的插入行方法
         * 这个方法是依赖于插入行按钮的,所以跟js模拟插入行按钮的点击动作是差不多的效果:
         * 比如B1单元格按钮:contentPane.getWidgetByCell('B1').element.children().trigger('click');
         *
         *     @example
         *     contentPane.appendReportRow("B1", 0, 2);//调用B1单元格的插入行按钮的插入行 并插入两行
         *
         * @param location 插入行按钮所在的位置
         * @param reportIndex sheet序号
         * @param count 行数
         */
        appendReportRow: function(location, reportIndex, count) {
            this._appendDeleteReportRow('append', arguments);
        },

        /**
         * 删除行按钮使用的删除行方法
         *
         *     @example
         *     contentPane.deleteReportRow("C2", 0, 1);//调用C2单元格的删除行按钮进行删除行
         *
         * @param location 删除行按钮所在的位置
         * @param reportIndex sheet序号
         * @param count 行数 删除行传不传都是删除1行
         */
        deleteReportRow: function(location, reportIndex, count) {
            this._appendDeleteReportRow("delete", arguments);
        },

        undeleteReportRow: function(location, reportIndex, count) {
            this._appendDeleteReportRow("undelete", arguments);
        },

        _appendDeleteReportRow: function(type, args) {
            // james:执行事件 beforeappend/delete
            if (this.fireEvent('before' + type) === false) {
                return;
            }

            this.stopEditing();
            // 插入新行前注销点击事件
            this.curLGP.unfocus();

            var location = FR.id2Location(args[0]);
            if (location == null) {
                return;
            }
            var tableId = this.curLGP.tableID;
            doSave.call(this, {
                params: {
                    op: "fr_write",
                    cmd: type + "_w_data", // append_w_data || delete_w_data || undelete_w_data
                    crow: location.row,
                    ccolumn: location.col,
                    reportIndex: args[1],
                    __cutpage__: this.options.cutpage,
                    pn: this.currentPageIndex,
                    beforePoint: false,
                    tableId: tableId,
                    count: args[2]
                },
                fn: function (res) {
                    var text = res.responseText;
                    var reObject = FR.jsonDecode(text);
                    if (reObject.exception) {
                        FR.Msg.toast(reObject.exception);
                    } else {
                        //hiram_write 局部刷新处理
                        if (reObject.isReload === "false") {
                            if (reObject.cmd == "appendRow") {
                                var $table = $(reObject.insertRow);
                                var $trs = $("tr[tridx]", $table);
                                this.curLGP.appendRow(reObject.startIndex, $trs, reObject.mergeCells);
                                this.curLGP.$fec = reObject.fec;
                                this.curLGP._selectFirstTD();
                                //Sean:重新获取下焦点,否则如果点击插入(删除)行按钮后,焦点会转到按钮控件上去,keydown会失效
                                this.curLGP.onfocus();
                                //hiram 刷新数据,延时一点,让插入的行先显示出来再刷新
                                setTimeout(function () {
                                    _g().refreshData(_g().curLGP.idx)
                                }, 10);
                            } else if (reObject.cmd == "deleteRow") {
                                this.curLGP.deleteRow(reObject.startIndex, reObject.len, reObject.mergeCells);
                                this.curLGP.onfocus();
                                if (!this.curLGP.isSelectable(this.curLGP.currentTDCell) && $(this.curLGP.currentTDCell).attr('id')) {
                                    var cr = FR.id2ColumnRow($(this.curLGP.currentTDCell).attr('id'));
                                    if (cr.row > 0) {
                                        var pCell = this.curLGP.getTDCell(cr.col, cr.row - 1);
                                        if (this.curLGP.isSelectable(pCell)) {
                                            this.curLGP.$fec = {col: cr.col, row: cr.row - 1};
                                        }
                                    }
                                    this.curLGP._selectFirstTD();
                                }
                                setTimeout(function () {
                                    _g().refreshData(_g().curLGP.idx)
                                }, 10);
                            }
                        } else {
                            this.reloadCurLGPPane(reObject.fec);
                        }
                        var arr = reObject.refreshSheetList;
                        if (arr && $.isArray(arr) && arr.length > 0) {
                            for (var i = 0; i < arr.length; i++) {
                                var idx = parseInt(arr[i]);
                                if (idx != _g().curLGP.idx) {
                                    _g().lgps[idx].loaded = false;
                                }
                            }
                        }
                    }
                    // james:afterappend/delete事件
                    this.fireEvent('after' + type);
                    refreshWidgets();
                }.createDelegate(this)
            });
        },

        /**
         * 工具栏增加记录
         *
         *     @example
         *     contentPane.appendReportRC(1);
         *
         * @param count 增加的行数
         * @param cell 增加的格子位置 一般不传这个参数用的是当前焦点所在格子
         */
        appendReportRC: function(count, cell) {
            this._appendDeleteReportRC("append", arguments);
        },

        /**
         * 工具栏的删除记录
         *
         *     @example
         *     contentPane.deleteReportRC();
         *
         * @param cell 删除的位置 一般不传这个参数用的是当前焦点所在格子
         */
        deleteReportRC: function(cell) {
            this._appendDeleteReportRC("delete", arguments);
        },

        _appendDeleteReportRC: function(type, args) {
            if (this.fireEvent('before' + type) === false) {
                return;
            }
            this.stopEditing();
            var crows = [];
            var ccols = [];
            var currentIdx = this.curLGP.idx;
            var tableId = this.curLGP.tableID;
            var cmd = "";
            if (type == "append") {
                cmd = "append_rc_data"
            } else {
                cmd = "delete_rc_data"
            }
            var reqConfig = {
                params: {
                    op: "fr_write",
                    cmd: cmd,
                    reportIndex: currentIdx,
                    __cutpage__: this.options.cutpage,
                    pn: this.currentPageIndex,
                    beforePoint: false,
                    tableId: tableId,
                    count: args[0]
                },
                fn: function (res) {
                    var text = res.responseText;
                    var reObject = FR.jsonDecode(text);
                    if (reObject.exception) {
                        FR.Msg.toast(reObject.exception);
                    } else {
                        this.reloadCurLGPPane(reObject.fec);
                    }
                    // james:afterappend/delete事件
                    this.fireEvent('after' + type);
                    refreshWidgets();
                }.createDelegate(this)
            };
            var targetCells = args[1];
            //wei : count参数只是针对添加行时才有意义,所以应该支持deleteReportRC(targetCells)的写法。
            if (!targetCells && type == 'delete') {
                targetCells = args[0];
            }
            if (!targetCells) {
                targetCells = $(this.curLGP.currentTDCell).attr("id");
            }
            if ($.isArray(targetCells)) {
                for (var c = 0, len = targetCells.length; c < len; c++) {
                    var loc = FR.id2Location(targetCells[c]);
                    crows.push(loc.row);
                    ccols.push(loc.col);
                }
            } else {
                var location = targetCells ? FR.id2Location(targetCells) : null;
                if (location == null) {
                    FR.Msg.toast(FR.i18nText("FR-Engine-Invalid_Cell"));
                    return;
                }
                crows.push(location.row);
                ccols.push(location.col);
            }
            reqConfig.params.crows = crows.join(",");
            reqConfig.params.ccols = ccols.join(",");

            doSave.call(this, reqConfig);
        },
        // 清空
        clear: function (showMsg) {
            var self = this;
            var btn = arguments[0];
            btn && btn.disable();
            var fn = function (showMsg) {
                FR.ajax({
                    url: FR.servletURL,
                    async: true,
                    data: {
                        op: 'fr_write',
                        cmd: 'clearstash',
                        sessionID: FR.SessionMgr.getSessionID()
                    },
                    type: 'post',
                    success: function (res, status) {
                        if (showMsg) {
                            if (res && res === "failed") {
                                FR.Msg.toast(FR.i18nText('FR-Engine_Failed'));
                            } else {
                                FR.Msg.toast(FR.i18nText('FR-Engine_Successfully'));
                            }
                        }
                    }
                });
            };
            if (showMsg === false) {
                fn.apply(this, arguments);
            } else {
                FR.Msg.confirm(FR.i18nText("FR-Engine-Write_Stash"), FR.i18nText("FR-Engine-Write_Are_Stashed_Clear"), function (result) {
                    if (result) {
                        fn.apply(self, arguments);
                    }
                });
            }
            btn && btn.enable();
        },
        // 暂存
        stash: function (showMsg) {
            var btn = arguments[0];
            btn && btn.disable();
            this.saveReport(function () {
                FR.ajax({
                    url: FR.servletURL,
                    async: true,
                    data: {
                        op: 'fr_write',
                        cmd: 'stash',
                        sessionID: FR.SessionMgr.getSessionID()
                    },
                    type: 'post',
                    success: function (res, status) {
                        if (showMsg) {
                            if (res !== 'success') {
                                FR.Msg.alert(FR.i18nText('FR-Engine-Write_Stash'), FR.i18nText('FR-Engine-Write_Stash_Failed_Msg'));
                            } else {
                                FR.Msg.toast(FR.i18nText('FR-Engine_Successfully'));
                            }
                        }

                    }
                });
            }, {
                removedirtys: false
            });
            btn && btn.enable();
        }
    };

    $.each(['append', 'delete', 'undelete'], function (idx, it) {
        P[it + 'ReportColumn'] = function () {
            P[it + 'ReportRow'].apply(this, arguments);
        }
    });


    /************************************************************************************************
     * 下面是一些私有的方法
     *************************************************************************************************/

    function refreshWidgets() {
        setTimeout(function () {
            contentPane.curLGP.write.refreshWidget();
        }, 1000)
    }

    function writeObject(value) {
        var xmlString = "";
        if (value == null) {
            return xmlString;
        }

        value = FR.jsonDecode(value);

        var xtype = "S", xcontent = null;
        if (typeof value == 'number') {
            xcontent = value;
            if (/\./.test("" + value)) {
                xtype = "D";
                // carl:因为sqltype中暂时没有BigInteger,所以都是BigDecimal吧
            } else if (("" + value).length >= 10) {
                xtype = "BigDecimal";
            } else {
                xtype = "I";
            }
        }
        // alex:因为是保存在attr里面的,所以日期型和Attachment的value用{}形式来表示
        else if (typeof value == 'object') {
            if (value.date_milliseconds != null) {
                xtype = "Date";
                xcontent = value.date_milliseconds;
            } else if (value.attach_id != null) {
                xtype = "Attachment";
                xcontent = value.attach_id;
            } else if ($.isArray(value) && value.length > 0 && value[0].attach_id) {
                xtype = "Attachments";
                xcontent = "";
                for (var i = 0; i < value.length; i++) {
                    if (i !== 0) {
                        xcontent += ",";
                    }
                    xcontent += value[i].attach_id;
                }
            } else if ($.isArray(value)) {
                xtype = "A";
                xcontent = FR.jsonEncode(value);
            } else if ($.isEmptyObject(value)) {
                xcontent = "";
            }
        } else if (typeof value == 'boolean') {
            xtype = "B";
        } else if (typeof value == 'string') {
            if (value.encryption === true) {
                xtype = "Encrypt";
                xcontent = FR.encrypt(value);
            } else {
                value = FR.jsonEncode(value);
                value = value.substring(1, value.length - 1);
            }
        }

        value = FR.encodePrecentPlus(value);

        if (xcontent == null) {
            xcontent = "" + value;
        }

        //cjkEncode the value to avoid the disorder value
        //Attention!!! the "<![CDATA[]]>" is also be cjkEncoded
        return "<O t=\"" + xtype + "\">" +
            "<![CDATA[" + FR.htmlSpaceDecode(("" + xcontent).replace(/\n/ig, "\\\nn")) + "]]>" +
            "</O>";
    }

    /**
     * write Value of tdCell
     */
    function writeCellValue(tdCell) {
        var $td = $(tdCell);
        var formula = $td.attr("fm");
        var value = $td.attr('cv');
        if (formula != null) {
//            return "<O t=\"RFormula\"><Attributes>" + FR.cjkEncode("<![CDATA[" + FR.htmlSpaceDecode(("" + formula).replace(/\n/ig, "\\\nn")) + "]]>")
//                + "</Attributes>" + writeObject(value)
//                + "</O>";
            return "<O t=\"RFormula\"><Attributes>" + "<![CDATA[" + FR.htmlSpaceDecode(("" + formula).replace(/\n/ig, "\\\nn")) + "]]>"
                + "</Attributes>" + writeObject(value)
                + "</O>";
        }

        return writeObject(value);
    }

    /*
     * 为什么取名字呢doSave呢,因为ajax传输的参数里带有reportXML,服务器端必然会保存一下
     * options {
     * 		params:此次ajax传输需要的参数
     * 		fn:此次ajax传输的callback
     * }
     *
     * doSave中用ajax的同步传输,不用异步传输
     */
    function doSave(options) {
        // carl:这里的同步ajax会和ui.dialog.js中遮盖层create时的setTimeout方法冲突,导致bug0002671
        // 暂时没有好的解决办法,或者重写ui.dialog的遮盖。这里用一个变量来判断是否延迟遮盖,详细情况见bug0002671陈述
        this.stopEditing();

        FR.ajax({
            url: FR.servletURL,
            type: 'POST',
            async: false,
            data: $.extend({
                op: "fr_write",
                cmd: "save_w_content",
                sessionID: this.currentSessionID,
                reportXML: this.generateReportXML(options.params && options.params.removedirtys !== false),
                cutPage: this.options.cutpage
            }, options.params), // 默认op为"write_saveContent",纯粹保存一下数据
            complete: (options.fn || FR.emptyFn).createSequence(FR.hideLoadingDialog) // alex:关掉loadingDialog的对话框
        });
    }

    return P;
}());

/*
 * alex:FormLoGicalPane
 */
FR.WLGP = function (config) {
    config = config || {};
    this.initialConfig = config;
    $.extend(this, config);

    this.loaded = false;
}

/**
 * 填报的逻辑页面
 * @class FR.WLGP
 * @extends FR.OB
 */
FR.extend(FR.WLGP, FR.OB, /**@class FR.WLGP*/function () {
    //default IE
    var tadjst = -1, ladjst = -1, wadjst = 3, hadjst = 3, etadjst = 1, eladjst = 1, ewadjst = -1, ehadjst = +2;
    if (FR.Browser.r.gecko || FR.Browser.r.opera) {//firefox or opera
        tadjst = -2, ladjst = -2, wadjst = -3, hadjst = -3, etadjst = 0, eladjst = 0, ewadjst = -1, ehadjst = +1;
    } else if (FR.Browser.r.webkit) {//for safari and chrome
        tadjst = -1, ladjst = -1, wadjst = -3, hadjst = -3, etadjst = 1, eladjst = 1, ewadjst = +1, ehadjst = +3;
    }
    var UP = 1, DOWN = 2, LEFT = 3, RIGHT = 4, EE = FR.keyCode;// KeyCode的缩写
    var oldSelectedCell;

    function isCell(dom) {
        var $dom = $(dom);
        return $dom.is('td') && $dom.attr('id') && $dom.attr('id').match(/^[A-Z]+\d+-\d+-\d+$/);
    }

    return {
        getehadjst: function () {
            return ehadjst;
        },

        getewadjst: function () {
            return ewadjst;
        },
        // 冻结的时候是relative的 内部的不要再做偏移
        getSCOffsetLeft: function () {
            return this.isFrozen() ? 1 : this.$sheet_container[0].offsetLeft;
        },
        getSCOffsetTop: function () {
            return this.isFrozen() ? 1 : this.$sheet_container[0].offsetTop;
        },

        /**
         * 检查当前页面是否是冻结的
         * e.g. contentPane.curLGP.isFrozen();
         * @return {boolean}
         */
        isFrozen: function () {
            return $('.frozen-table', this.$sheet_container).length > 0;
        },
        /**
         * $container, content actually be added, which is a jQuery Object, the contentPane or the selected tab of the TabPane
         */
        $container: null,
        /**
         * writePane:FR.WritePane this lgp belongs to
         */
        writePane: null,
        /*
         * idx in writePane
         */
        idx: 0,

        keyevent: null,

        __moving__: false, // 是否正在移动中...
        currentPageIndex: 0,
        gotoFirstPage: function () {
            this.gotoPage(1);
        },
        gotoPreviousPage: function () {
            if (this.currentPageIndex <= 1) {
                return;
            }
            this.gotoPage(this.currentPageIndex - 1);
        },
        gotoNextPage: function () {
            this.gotoPage(this.currentPageIndex + 1);
        },
        gotoLastPage: function () {
            this.gotoPage(this.reportTotalPage);
        },
        gotoPage: function (page, async) {
            var cutPage = this.writePane.options.cutpage;
            if (page != null) {
                this.writePane.stopEditing();
            }
            //重置快捷键选中单元格
            this.lastRow = null;
            this.lastCol = null;
            //shoc:  __cutpage__:v 按行分页
            if (cutPage == "v" || cutPage == 'w') {
                // 没有page参数,说明是刚加载时候
                if (page == undefined || page == null || this.reportTotalPage == undefined) {
                    this.currentPageIndex = 1;
                    page = 1;
                }
                else {
                    //有效的页码,传递
                    if (typeof page == 'number' && page > 0 && page <= this.reportTotalPage) {
                        this.currentPageIndex = page;
                        if (this.dirtyCell.length > 0) {
                            this.saveCurrentPage();
                        }
                    }
                    //无效的页码,提示
                    else {
                        FR.Msg.toast("Invalid Page Number");
                        return;
                    }
                }
            }

            this.$container.__load__({
                url: FR.servletURL,
                scripts: true,
                timeout: 600000,
                // richer:随便加一个随机参数,避免缓存影响
                params: {op: "fr_write", cmd: "read_w_content",
                    sessionID: this.writePane.currentSessionID,
                    reportIndex: this.idx,
                    browserWidth: document.body.clientWidth,
                    iid: Math.random(), async: arguments[1], __cutpage__: cutPage, pn: page},
                loadHtml: function (html) {
                    if (FR.Browser.r.isInnerHtmlSuitable) {
                        for (var i = 0; i < this.length; i++) {
                            this[i].innerHTML = html;
                        }
                    }else{
                        this.html(html);
                    }
                },
                callback: function (el, success, res, options) {
                    if (success) {
                        FR._executeScriptFromHtml(this.$container.html());
                        this.initLGPComponent();
                    } else {
                        //如果不成功的话,也要把报错信息写在页面里
                        this.$container.html(res.responseText);
                    }
                    this.writePane.curLGP = this;
                    // alex:设置this.$container为当前的formPane.ContentContainer
                    this.writePane.$currentContentContainer = this.$container;
                    this.writePane.isLoadingPage = -1;
                    delete this.loaded;

                    //fire formPane的afterload事件,并把this作为参数传过去
                    this.writePane.fireEvent(FR.Events.AFTERLOAD, this);
                    this.writePane.afterLoad();

                    /*
                     * alex:应该在afterload之后再选中单元格
                     * 因为客户可能会在afterload事件上添加监听,监听当cellselect时要做些事情
                     */
                    if (success) {
                        //重新加载后,还是清空原先的好点,否则不仅浪费操作还容易出问题
                        this.currentTDCell = null;
                        this.editorEl = null;
                        this.cellEditing = null;
                        this._selectFirstTD();
                    }

                }.createDelegate(this)
            });
        },
        /*
         * 加载Panel的内容
         */
        loadLGPPane: function () {
            var self = this;
            if (this.writePane.isLoadingPage == this.idx) {
                return;
            }

            this.dirtyCell = [];

            this.writePane.fireEvent(FR.Events.STARTLOAD);
            this.writePane.isLoadingPage = this.idx;

            // alex:下面强制设置innerHTML为空字符串,jQuery.html()方法会调用empty(),很费时间
            // 客户嫌刷新幅度过大,屏了吧
//	    	this.$container[0].innerHTML = "";
            this.gotoPage(_g().currentPageIndex, arguments[0]);
            // 加载完给writePane也加个gotoPage方法,和分页预览统一,给工具栏的页码输入框使用
            this.writePane.gotoPage = function (index, anysc) {
                self.writePane.lgps[self.writePane.selectedIndex].gotoPage(index, anysc);
            }
        },

        /*
         * 初始化LGPComponent
         */
        initLGPComponent: function () {
            var self = this;

            this.$sheet_container = $('.sheet-container', this.$container);


            // richer:有冻结才把做layout
            if (this.isFrozen()) {
                // 这个sheet是可见的才做Layout 不可见的时候取到的尺寸都是0
                if (this.$sheet_container.parent().isVisible()) {
                    FR.layoutFrozen(this.$sheet_container, this.$sheet_container.offset().top);
                    this.frozenModified = true;
                }
                //wei : bug5374
                this.$container.css({
                    overflow: 'hidden'
                });
            }

            this._addGlance();

            if(this.isFrozen()) {
                /*
                 * wei:安卓部分机型,QQ/微信内置的QQ浏览器X5内核,冻结后滚动不了,各项数值都没问题,宽高,甚至滚动条都能在界面上看到,但是就是滚不动,
                 * 手指缩放一下后就能滚动,看了1天也没看出什么名堂,这样重新append一下就能滚动,先这样处理吧。
                 */
                this.$container.append(this.$sheet_container);
            }

            //end
            this.$editor = $('.x-editor', this.$container);
            this.$editor.mouseover(function () {
                self.$editor.addClass('glance-editor-focus');
            }).mouseout(function () {
                self.$editor.removeClass('glance-editor-focus');
            });

            // 保存联动使用到但还没生成的控件所在ID对应的联动的控件
            this.depEditors = {};
            this.$scrollable = this.$container; // 设置滚动对象为$container
            this.$table = $('.x-table', this.$container);
            // denny: 报表tableID, 用来标识单元格的唯一性。
            this.tableID = this.$table.attr("id");
            this.write = this.$sheet_container.asComponent({type: "fr_write",
                selector: 'td[widget]',
                resolveVariable: function (variable) {
                    // alex:执行getCellValue("B2")
                    return self.getCellValue(variable);
                }
            });
            this.write.lgp = this;
            //wei : 处理水印和鼠标移上去显示控件  + 初始化联动
            var widgets = $('td[editor],td[widget]', this.$sheet_container);
            this.write.WidgetMgr.DependenceMgr._dependenceRelationMap = {};
            this.write.WidgetMgr.DependenceMgr._dependenceInitedMap = {};
            this._addGlanceEventAndCalculateDependence(widgets);
            var arr = this.write.WidgetMgr.DependenceMgr.getWidgetShouldInitDependence();
            for (var i = arr.length - 1; i >= 0; i--) {
                self.write._initDependenceRelationWidgetByKey(arr[i]);
            }
            //Sean: this.$fD是选中可编辑单元格时出现的边框线。
            this.$fD = {};
            this.$fD.ftop = $('#fDtop', this.$container);
            this.$fD.fleft = $('#fDleft', this.$container);
            this.$fD.fbottom = $('#fDbottom', this.$container);
            this.$fD.fright = $('#fDright', this.$container);
            this.$fD.fdot = $('<div/>');

            this.table_width = this.$table.find("colgroup:eq(0)").children().length;
            this.table_height = this.$table.find('tbody:eq(0)').children().length;

            // 为$sheet加事件
            // alex:单击选中的某个格子进入编辑状态,原来是用mousedown事件,$editorComponent.focus不了
            //bug84988,80990这边还是要用click事件。80990的问题通过屏蔽一些特殊违法操作解决。
            this.$sheet_container.click(function (e) {
                var src = e.target;
                var secell;
                // 可能点了格子内部的什么,默认选出来

                if (!isCell(src)) {
                    var $td = $(src).parents('td:eq(0)')
                    if ($td.length > 0 && isCell($td[0])) {
                        secell = $td[0];
                    }
                } else {
                    secell = src;
                }
                // 假如已经选中了,就进入编辑
                if (secell) {
                    if (self.currentTDCell && $(self.currentTDCell).attr("id") == $(secell).attr("id")) {
                        self.editTDCell();
                    } else if ($(secell).attr('widget') || self.writePane.editOnClick) {
                        self.selectTDCell(secell);
                        self.editTDCell();
                    } else {
                        self.selectTDCell(secell);
                    }
                }
            }).dblclick(function (e) {
                var src = e.target;
                if (isCell(src)) {
                    if (FR.Browser.isIE()) {
                        if (self.currentTDCell && $(self.currentTDCell).attr("id") == $(src).attr("id")) {
                            self.editTDCell(src);
                        } else {
                            self.selectTDCell(src);
                            self.editTDCell(src);
                        }
                    } else {
                        self.editTDCell(src);
                    }
                }
            });

            this.$sheet_container.css("display", "");
            // 对onfocus的激活处理
            //b:mousedown来判断不是很好。。居然有combobox的判断
            $(document).mousedown(function (e) {
                self[FR.isAncestor(self.$sheet_container[0], e.target)
                || (FR.$view_container && FR.isAncestor(
                    FR.$view_container[0], e.target))
                    ? 'onfocus'
                    : 'unfocus']();
            });

            // carl:觉得不是太好的处理,获得焦点时注册事件,失去焦点时移除事件
            this.keyevent = {scope: this, fn: this._onKeyDown};
            this.onfocus();
        },

        _addGlance:function() {
            var self = this;
            //Sean: this.$glance是选中可编辑单元格时出现在单元格右上角指示单元格可编辑的小图标的DOM和属性。
            this.$glance = {};
            this.$glance.top = $('.gltop', this.$container);
            this.$glance.left = $('.glleft', this.$container);
            this.$glance.bottom = $('.glbottom', this.$container);
            this.$glance.right = $('.glright', this.$container);
            this.$glance.img = $('<div/>').appendTo(this.$container)
                .addClass("glance-editor-img").attr("title", FR.i18nText("FR-Engine_Edit")).click(
                    function (e) {
                        var tdCell = self.$glance.tdCell;
                        if (tdCell) {
                            self.removeGlanceEditor(e);
                            // selectTDCell顺利执行完才editTDCell,bug31946
                            if (self.selectTDCell(tdCell) !== false) {
                                self.editTDCell(tdCell);
                            }
                        }
                    }).hide();

            //hiram_write 把$glance的top,left等加入到一个div里
            var oldParent = this.$glance.top.parent();
            this.$glance.div = $('<div id="glanceDiv" style="position:absolute;top:0px;left:0px"><div>');
            this.$glance.div.append(this.$glance.top);
            this.$glance.div.append(this.$glance.left);
            this.$glance.div.append(this.$glance.bottom);
            this.$glance.div.append(this.$glance.right);
            this.$glance.div.append(this.$glance.img);
            //$glance.img是跟随glanceDiv显示隐藏了,初始时会显示在左上角,设为-999px隐藏起来
            this.$glance.img.css("top", "-999px");
            this.$glance.img.show();
            this.$glance.top.show();
            this.$glance.left.show();
            this.$glance.bottom.show();
            this.$glance.right.show();
            this.$glance.div.appendTo(oldParent);
            //当从水印div中移出时要remove水印
            this.$glance.div.children().mouseleave(function (e) {
                self.removeGlanceEditor(e);
            });
        },

        //_glanceEvent
        _addGlanceEventAndCalculateDependence: function (widgets) {
            var self = this;
            for (var idx = 0, len = widgets.length; idx < len; idx++) {
                var widget = widgets[idx];

                $(widget).mouseenter(function (e) {
                    var src = e.currentTarget;
                    if (!isCell(src)) {
                        return;
                    } else {
                        var isEditor = $(src).attr('editor');
                        if (isEditor) {
                            self.glanceTDCell(src);
                        }
                    }
                }).mouseleave(function (e) {
                    self.removeGlanceEditor(e);
                });


                // richer:获取联动的关联格子
                var shouldInit = false;
                var attrJson = $(widget).attr('editor');
                if (!attrJson) {
                    attrJson = $(widget).attr('widget');
                    shouldInit = true;
                }
                var attr = null;
                if (shouldInit) {
                    attr = FR.jsonDecode(attrJson);
                    self.write.WidgetMgr.DependenceMgr.addWidgetShouldInitDependence(attr.location);
                    self.write.WidgetMgr.DependenceMgr.addWidgetShouldInitDependence(attr.widgetName);
                }

                if (!$(widget).attr('hasWatermark') && !$(widget).attr('hasDependece') && !$(widget).attr('hasAttachment')) {
                    continue;
                }

                if (!attr) {
                    attr = FR.jsonDecode(attrJson);
                }
                if (!(!attr.watermark || attr.value || attr.value === 0)) {
                    FR.$defaultImport('/com/fr/web/core/js/jquery.watermark.js', 'js');
                    if(!attr.isEditable){
                        $(widget).text(attr.watermark).css({
                            'color': $(widget).getwatermarkcolor()
                        });
                    }
                    $(widget).addClass('watermarkCell');
                }
                if (attr.type == "multifile") {
                    var cv = $(widget).attr('cv');
                    cv && (cv = FR.jsonDecode(cv));
                    if (($.isArray(cv) && cv.length > 0) || (cv && cv.attach_id && (cv = [cv]))) {
                        this.previewAttachment($(widget), attr.maxlength === 1 && cv[0].attach_type == "image" ? cv[0] : cv);
                    }
                }

                if (attr.dependenceMap || attr.dependence) {
                    var location = attr.location;
                    var finalDependence = {};
                    if (attr.dependenceMap) {
                        finalDependence = attr.dependenceMap;
                    } else if (FR.isArray(attr.dependence)) {
                        finalDependence = attr.dependence;
                    }
                    $.each(finalDependence, function (key, item) {
                        var idOrName = item.startWith("$") ? item.substring(1) : item;
                        self.write.WidgetMgr.DependenceMgr.addDependenceRelation(idOrName, location);
                    });

                }
            }
        },

        //hiram 隐藏glance
        _hideGlance: function () {

            if (!this.$glance.oldTdCell) {
                this.$glance.oldTdCell = this.$glance.tdCell;
            } else {
                if (this.$glance.oldTdCell == this.$glance.tdCell) {
                    return;
                } else {
                    this.$glance.oldTdCell = this.$glance.tdCell;
                }
            }
            this.$glance.div.hide();
            this.$glance.tdCell = null;
        },
        _showGlance: function (tdCell) {
            var $tdCell = $(tdCell);
            var top = $tdCell.parent()[0].offsetTop;
            var bounds = this.getTDCellBounds(tdCell);
            var left = $(".fr-fileupload-download-all", tdCell).length > 0 ? 18 : 0;
            this.$glance.img.css({
                top: bounds.top + etadjst - 2,
                left: bounds.left + eladjst - 20 + bounds.width - left
            });
            this.$glance.top.css({top: bounds.top, left: bounds.left, width: bounds.width - 2});
            this.$glance.left.css({top: bounds.top + 1, left: bounds.left, height: bounds.height - 4});
            this.$glance.bottom.css({top: bounds.top + bounds.height - 3, left: bounds.left, width: bounds.width - 2});
            this.$glance.right.css({top: bounds.top + 1, left: bounds.left + bounds.width - 3, height: bounds.height - 4});
            this.$glance.div.show();
        },
        // 选中第一个可选的格子
        _selectFirstTD: function () {
            var fecTD;
            // carl:看看有没有设定的需要首先选的格子
            if (this.$fec) {
                fecTD = this.getTDCell(this.$fec);
                if (this.isSelectable(fecTD)) {
                    this.selectTDCell(fecTD, false);
                } else {
                    fecTD = null;
                }
            }
            // alex:选中第一个可选中的格子
            if (!fecTD) {
                var cell = $(".fst-edt", this.$container);
                if (cell.length > 0) {
                    this.selectTDCell(cell[0], false);
                    return false;
                }
            }
        },

        //hiram 下面的都是插入行局部刷新的
        appendRow: function (insertIndex, $trs, mergeCells) {
            var helper = FR.WLGP.RowHelper;
            this._down_location_widgets(insertIndex, $trs.length, helper);
            this._down_tr_id(insertIndex, $trs.length, helper);
            this._down_td_id(insertIndex, $trs.length, helper);
            this._update_widgetAttr(insertIndex, $trs.length, helper);
            this._clipTrs($trs, mergeCells);


            var widgets = $('td[widget]', $trs);
            var editors = $('td[editor]', $trs);
            this._addGlanceEventAndCalculateDependence(editors);
            widgets.each(function (idx, dom) {
                if (dom.hasInit !== true) {
                    _g().curLGP.write.addWidget($(dom));
                }
            });

            // 填报分页的话上一行可能在上一页这时候需要用下一行
            var pre = $("tr[tridx='" + (insertIndex - 1) + "']", this.$container);
            if (pre.length > 0) {
                pre.after($trs);
            } else {
                $("tr[tridx='" + (insertIndex + 1) + "']", this.$container).before($trs);
            }

            this.table_height && this.table_height++;
            this._changeSpan4Array(mergeCells, $trs.length);
        },

        deleteRow: function (start, len, mergeCells) {
            var self = this;
            $("tr[tridx]", this.write.options.renderEl).each(function (index, tr) {
                var $tr = $(tr);
                var tridx = $tr.attr("tridx");
                if (tridx >= start && tridx < start + len) {
                    $tr.height("0px");
                    $tr.css("display", "none");
                    self.addDelFlag4offline($tr);
                }
            });
            if (this.table_height && --this.table_height < 0) {
                this.table_height = 0;
            }
            this._changeSpan4Array(mergeCells, -len);
        },

        addDelFlag4offline : function($tr){

        },
        //有时后台传过来的trs还会有空白单元格,这应该是合并单元格占的位,把这部分去掉
        _clipTrs: function ($trs, mergeCells) {
            if (typeof mergeCells === "undefined") {
                return
            }
            ;
            for (var i = 0; i < mergeCells.length; i++) {
                var colName = FR.digit2Letter(mergeCells[i].col + 1);
                //conName为A,B..,去掉某列所有单元格
//                $('#' + colName + "-" + this.idx + "-" + this.tableID).remove();
                $("td[id^='" + colName + "']", $trs).remove();
            }
        },
        //改变指定的单元格rowspan
        _changeSpan: function ($td, len) {
            if (typeof $td.attr("rowspan") !== "undefined") {
                var rowspan = parseInt($td.attr("rowspan"));
                $td.attr("rowspan", rowspan + len);
            } else {
                $td.attr("rowspan", 1 + len);
            }
        },
        //{"sessionID":"23856","location":"A4","widgetUrl":"/WebReport/ReportServer?op=widget&location={\"column\":0,\"row\":3,\"reportIndex\":0}&sessionID=23856","regex":"","invisible":false,"value":"name3","needSubmit":true,"type":"text","reportIndex":0,"disabled":false,"render":true}
        //tds [{col:1, row:2}, {col:6, row:2}]
        _changeSpan4Array: function (tds, len) {
            for (var i = 0; i < tds.length; i++) {
                var cellName = FR.columnRow2CellStr(tds[i]);
                this._changeSpan($("#" + cellName + "-" + this.idx + "-" + this.tableID), len);
            }
        },
        //把write.location_widgets中的widgets往下移,start开始移动的行,len长度
        _down_location_widgets: function (start, len, helper) {
            //cellStr2ColumnRow (name)   // "A3"->{col, row}
            var olds = this.write.location_widgets;
            var news = {};
            for (var location in olds) {
                if (helper.compare4CellStr(location, start) < 0) {
                    news[location] = olds[location];
                } else {
                    var newLocation = helper.add4CellStr(location, len);
                    news[newLocation] = olds[location];
                    var newWidget = news[newLocation];
                    newWidget.options.location = newLocation;
                    newWidget.options.widgetUrl = this._replaceWidgetURLStr(newWidget.options.widgetUrl, FR.cellStr2ColumnRow(newLocation));
                    if (newWidget.options.data) {
                        this._updateUrlInWidgetData(newWidget.options.data, newWidget.options.widgetUrl);
                    }
                }
            }
            this.write.location_widgets = news;
        },


        _updateUrlInWidgetData: function (data, url) {
            if (data.options.dataReader) {
                this._updateOptionsUrl(data.options.dataReader, url)
            }
            if (data.options.dataSource) {
                this._updateOptionsUrl(data.options.dataSource, url)
            }
        },

        _updateOptionsUrl: function (o, url) {
            if (o.options && o.options.url) {
                o.options.url = url;
            }
        },
        _down_tr_id: function (start, len, helper) {
            //r-2-0
            $("tr[tridx]", this.write.options.renderEl).each(function (index, dom) {
                var $dom = $(dom);
                var tridx = $dom.attr("tridx");
                if ($dom.attr("tridx") >= start) {
                    tridx = len + parseInt(tridx);
                    $dom.attr("tridx", "" + tridx);
                    dom.id = helper.add4TrId(dom.id, len);
                }
            });
        },
        _down_td_id: function (start, len, helper) {
            var lgp = this;//,lgp.write.options.renderEl
            $("td[id]", lgp.write.options.renderEl).each(function (index, dom) {
                var $dom = $(dom);
                var cr = FR.id2ColumnRow(dom.id);
                if (cr.row >= start) {
                    cr.row += len;
                    dom.id = FR.columnRow2CellStr(cr) + "-" + lgp.idx + "-" + lgp.tableID;
                }
            });
        },
        //更新单元格的widget和editor属性里的location
        _update_widgetAttr: function (start, len, helper) {
            var lgp = this;

            $("td[editor],td[widget]", lgp.write.options.renderEl).each(function (index, dom) {
                var $dom = $(dom);
                var cr = FR.id2ColumnRow(dom.id);
                if (cr.row >= start) {
                    if (typeof($dom.attr("editor")) == "undefined") {
                        var editor = $dom.attr('widget');
                        var newEditor = lgp._replaceEditorStr(editor, cr);
                        $dom.attr("widget", newEditor);
                    } else {
                        var editor = $dom.attr('editor');
                        var newEditor = lgp._replaceEditorStr(editor, cr);
                        $dom.attr("editor", newEditor);
                    }
                }
            });
        },


        _replaceWidgetURLStr: function (urlStr, cr) {
            var newUrlStr = urlStr.replace(/\"column\":[0-9]{1,3},\"row\":[0-9]{1,3}/, "\"column\":" + cr.col + ",\"row\":" + cr.row);
            return newUrlStr;
        },

        _replaceEditorStr: function (editorStr, cr) {
            //{\"column\":1,\"row\":2,\"reportIndex\":0}
            var newEditor = editorStr.replace(/\\\"column\\\":[0-9]{1,3},\\\"row\\\":[0-9]{1,3}/, "\\\"column\\\":" + cr.col + ",\\\"row\\\":" + cr.row).replace(/"location":"[A-Z]{1,3}[0-9]{1,3}/, '"location":"' + FR.columnRow2CellStr(cr));
            return newEditor;
        },
        //hiram 插入行方法End


        onfocus: function () {
            FR.Keys.reg(this.keyevent)
        },

        unfocus: function () {
            FR.Keys.unreg(this.keyevent)
        },

        getCellValue: function (columnIndex, rowIndex) {
            return FR.getCellValue(this._get$TDCell(columnIndex, rowIndex));
        },

        setCellValue: function (columnIndex, rowIndex, cv, presentValue, hyperlink) {
            if (arguments.length === 2) {
                cv = arguments[1];
                rowIndex = null;
            }
            var $tdCell = this._get$TDCell(columnIndex, rowIndex);
            var $tr = $tdCell.parent();
            var oriHeight = $tr.isVisible() ? $tr.height() : 0;
            FR.setCellValue($tdCell, cv);
            var editorO = $tdCell.attr('editor') || $tdCell.attr('widget');
            if (editorO) {
                //设置单元格值后还需要设置控件值。如果控件已经初始化了,调到其setValue方法,否则改变下editorO.value属性
                editorO = FR.jsonDecode(editorO);
                if (this.write.location_widgets && this.write.location_widgets[editorO.location]) {
                    var cellWidget = this.write.location_widgets[editorO.location];
                    cellWidget.setValue(this.formatCellValue($tdCell, cv, presentValue));
                    if(editorO.isEditable && cellWidget.editComp){
                        cellWidget.editComp.addClass('dirty');
                    }
                } else {
                    editorO.value = cv;
                    if ($tdCell.attr('editor')) {
                        $tdCell.attr('editor', FR.jsonEncode(editorO));
                    } else {
                        $tdCell.attr('widget', FR.jsonEncode(editorO));
                    }
                }
            }
            $tdCell.addClass("dirty");
            if (hyperlink) {
                var hyperlinkSpan = $("span", $tdCell);
                if(hyperlinkSpan.length === 0){
                    hyperlinkSpan = $tdCell;
                }

                hyperlinkSpan.attr("onclick", hyperlink);
            }
            this.displayTDCell($tdCell, cv, presentValue);
            FR.modifyRowHeightAfterContentChange($tr, oriHeight);
            if(editorO){
                this.resizeWidgetsAfterTrChange($tr, oriHeight, editorO.isEditable);
            }

        },

        formatCellValue : function(tdCell, cv, presentValue){
            var $tdCell = $(tdCell);
            var editorAttr = FR.jsonDecode($tdCell.attr('widget'));
            if(!editorAttr.isEditable){
                return cv;
            }
            // carl : 隐藏的单元格不显示
            if ($tdCell.is('.cehide')) {
                return  '';
            }

            // BUG0001372 填报中下拉框选值无法显示正确
            if (FR.isArray(cv)) {// james:如果cv是Array的话,那么目前的情况就是复选框会出现这样的结果,其他的编辑器目前全部是只返回一个值

                var content=this.calArrayTypeCV2Content(cv, $tdCell);

                return this.formatContent(content,$tdCell);
            } else {
                // alex:如果有present,要到服务器上去问一下,present之后是什么东西

                cv = this.calNormalTypeCV2Content(cv, $tdCell, presentValue);

                return this.formatContent(cv,$tdCell)
            }

        },

        showAsWidget: function ($tdCell) {

            return $tdCell.attr('widget') != null;

        },

        /*
         * alex:取得第i列的列宽
         * e.g. 获取当前sheet第三列的宽度contentPane.curLGP.getColumnWidth(2);
         */
        getColumnWidth: function (i) {
            if (i >= 0 && i < this.table_width) {
                // alex:原来是上面注释掉的那种写法,但在opera & safari里面会返回0,而不是实际的width
                return parseInt(this.$table.find("colgroup:eq(0)").children(":eq(" + i + ")").css('width'))
            }
            return 0;
        },

        /*
         * alex:取得第i行的行高
         * e.g. 获取当前sheet第三行的高度contentPane.curLGP.getRowHeight(2);
         */
        getRowHeight: function (i) {
            if (i >= 0 && i < this.table_height) {
                return this.$table.find("tbody:eq(0)").children().eq(i).height()
            }
            return 0;
        },

        /*
         * 键盘事件
         */
        _onKeyDown: function (e) {
            var k = e.keyCode;
            var curCell, editor, tmpWidget;
            var directEditFlag = false;
            curCell = this.writePane.curLGP.currentTDCell;
            if (curCell != null && $(curCell).attr('editor') != null) {
                editor = FR.jsonDecode($(curCell).attr('editor'));
                tmpWidget = contentPane.getWidgetByCell(editor.location);
            }
            if (curCell != null && $(curCell).attr('widget') != null) {
                directEditFlag = true;
                editor = FR.jsonDecode($(curCell).attr('widget'));
                tmpWidget = contentPane.getWidgetByCell(editor.location);
            }
            // delete 和 paste 需要判断控件 控件不可用或不可见的时候阻止掉
            if ((k == EE.DELETE || k == EE.BACKSPACE) || (e.ctrlKey && k === 86)) {
                if (tmpWidget && tmpWidget.options) {
                    // 控件可用并且可见的才能delete paste
                    if (!(tmpWidget.options.disabled === false && tmpWidget.options.invisible === false)) {
                        return;
                    }
                }
            }

            // p: delete.
            if (k == EE.DELETE || k == EE.BACKSPACE) {
                if (this.writePane.curLGP.cellEditing == null) {
                    if (tmpWidget != null && FR.getCellValue($(curCell)) !== "") {
                        // 控件可用并且可见的才能delete
                        if ((!tmpWidget.options) || (tmpWidget.options.disabled === false && tmpWidget.options.invisible === false)) {
                            // 改变td的显示值
                            this.writePane.curLGP.displayTDCell(curCell, "");
                            // 改变tdCell的值cv
                            this.writePane.curLGP.fireCellValueChange(curCell, "", null);
                            // 改变控件的值 editComp置空
                            tmpWidget.editComp && tmpWidget.editComp.val("");
                            tmpWidget.reset();
                            // reset()中包含有afteredit事件
                            tmpWidget.fireEvent(FR.Events.STOPEDIT);
                        }
                    }
                }
            }
            // ctrl + v
            else if (e.ctrlKey && k === 86) {
                var el;
                if (FR.Browser.isIE()) {
                    el = e.srcElement;
                } else {
                    el = e.target;
                }
                var tag = el.tagName;
                //alert(tag);
                // carl:事件会冒泡上来,假如是输入框之类的ctrl+v,就不理睬
                if (tag != "INPUT" && tag != "TEXTAREA") {
                    var cp = $("#cpTextArea");
                    cp.focus();
                    cp.select();
                    setTimeout(function () {
                        _g().pasteCells();
                    }, 50);
                } else {
                    setTimeout(function () {
                        _g().fireCurrentWidgetEvent(FR.Events.AFTEREDIT);
                    }, 50);
                }
            }
            // 按a-zA-Z0-9开始编辑(alex:在keydown事件里,好像a和A都是65,在keypress事件且在ie中a好像是97),[96~105]是右边的小键盘按出来的
            else if (k == EE.SPACE || k >= 48 && k <= 57 || k >= 65 && k <= 90 || k >= 96 && k <= 105 || k === 109 || k === 189 ||
                e.shiftKey && k === 187 || k === 107) {
                //bug:80990鼠标离开时事件在其他地方需要屏蔽掉键盘事件,不然提交数据有误
                if(directEditFlag && editor && !editor.isEditable){
                    e.stopEvent();
                    return;
                }
                if (this.writePane.curLGP.cellEditing == null) {
                    this.writePane.curLGP.editTDCell(null);
                    // alex:如果是按空格键,仅仅是开始编辑,不要把空格写到编辑器里面
                    if (k == EE.SPACE) {
                        e.stopEvent();
                    }
                }
            } else {
                var direction = 0;

                if (this.writeShortCuts == undefined) {
                    this.writeShortCuts = !this.getWriteShortCuts();
                }

                // richer:tab键左移
                if (e.shiftKey && k == EE.TAB) {
                    direction = this.writeShortCuts ? LEFT : UP;
                    // shift + enter键上移
                } else if (e.shiftKey && k == EE.ENTER) {
                    direction = this.writeShortCuts ? UP : LEFT;
                    // tab键右移
                } else if (!e.shiftKey && k == EE.TAB) {
                    direction = this.writeShortCuts ? RIGHT : DOWN;
                    // enter键下移
                } else if (!e.ctrlKey && k == EE.ENTER) {
                    direction = this.writeShortCuts ? DOWN : RIGHT;
                    // left键左移
                } else if (!e.ctrlKey && k == EE.LEFT) {
                    if (this.cellEditing != null) {
                        return;
                    }
                    direction = LEFT;
                    // right键右移
                } else if (!e.ctrlKey && k == EE.RIGHT) {
                    if (this.cellEditing != null) {
                        return;
                    }
                    direction = RIGHT;
                    // up键上移
                } else if (!e.ctrlKey && k == EE.UP) {
                    direction = UP;
                    // down键下移
                } else if (!e.ctrlKey && k == EE.DOWN) {
                    direction = DOWN;
                }

                if (direction === 0) {
                    return;
                }

                e.preventDefault();
                e.stopPropagation();
                this.writePane.curLGP.moveTDCell(direction);
            }
        },
        getWriteShortCuts: function () {
            var writeShortCuts;
            FR.ajax({
                url: FR.servletURL,
                data: {
                    op: 'fr_write',
                    cmd: "write_shortcuts",
                    sessionID: this.writePane.currentSessionID
                },
                async: false,
                complete: function (res, status) {
                    if (status == 'success') {
                        writeShortCuts = res.responseText == 'true'
                    }
                }
            });

            return writeShortCuts;
        },
        /*
         * 单元格值改变后
         */
        fireCellValueChange: function (tdCell, cv, fm, calnow) {

            if (tdCell == null) {
                return;
            }
            var $tdCell = $(tdCell);
            FR.setCellValue($tdCell, cv);

            var cal = false;
            if (fm == null) {
                if ($tdCell.attr('fm') != null) {
                    cal = true;
                }
                $tdCell.removeAttr("fm");
            } else {
                $tdCell.attr('fm', fm);
                cal = true;
            }
            $(tdCell).addClass('dirty');

            this.dirtyCell.push(tdCell);
            if ((cal || $tdCell.attr("frs") != null) && calnow !== false) {
                this.writePane.writeDirtyAndRemoteCal(this.idx, FR.id2ColumnRow($tdCell.attr("id")), cv, fm);
            }
            // richer:通知单元格改变,用于联动
            this.fireEvent(FR.Events.CELLVALUECHANGE, $(tdCell), cv);
        },
        /**
         * 填报翻页时候保存当前页面内容
         */
        saveCurrentPage: function () {
            if (this.dirtyCell && this.dirtyCell.length > 0) {
                var $tmpCell = $(this.dirtyCell[0]);
                this.writePane.writeDirtyAndRemoteCal(this.idx, FR.id2ColumnRow($tmpCell.attr("id")), $tmpCell.text());
            }
        },
        /**
         *计算下当前页
         */
        calCurrentPage: function () {
            if (this.dirtyCell && this.dirtyCell.length > 0) {
                var $dirtyCell = [];
                $.each(this.dirtyCell, function (i, tmpCell) {
                    $dirtyCell.push(FR.id2ColumnRow($(tmpCell).attr("id")))
                })
                this.writePane.writeDirtyAndRemoteCal(this.idx, $dirtyCell);
            }
        },

        /*
         * 把一个TD变成ColumnRowString
         */
        cut2ColumnRowString: function (td) {
            if (td == null) {
                return null;
            }

            var iid = $(td).attr("id");
            return iid.substring(0, iid.length - ('-' + this.idx).length - ('-' + this.tableID).length)
        },

        /*
         * 选中一片tdCell,暂时主要用于公式解析A1:C3这样的东西
         */
        getRangeTDCells: function (fc, fr, tc, tr) {
            var cells = [];
            for (var r = fr; r <= tr; r++) {
                for (var c = fc; c <= tc; c++) {
                    var tdCell = this.getTDCell(c, r);
                    if (tdCell) {
                        cells[cells.length] = tdCell;
                    }
                }
            }
            return cells
        },

        /**
         * dCell是否可被选中包括直接显示控件场景下的可编辑控件
         */
        isWeakSelectable: function(tdCell){
            return this.isSelectable(tdCell) || this.isEditableWidget(tdCell);
        },
        /**
         * 直接显示控件的时候可编辑控件和类似按钮控件之类的不可编辑控件通过这个来区分
         * @param tdCell
         * @returns {boolean} 是否是可以编辑的控件
         */
        isEditableWidget: function (tdCell){
            var widget = $(tdCell).attr("widget");
            if(widget && FR.jsonDecode(widget).isEditable){
                return true;
            }
            return false;
        },
        /*
         * 该dom tdCell是否可被选中
         */
        isSelectable: function (tdCell) {
            // richer:如果直接显示编辑器了,就不再需要编辑框了
            var text = $(tdCell).attr("editor");

            if (!text) {
                return false;
            }
            if (FR.jsonDecode(text).showOnLoad) {
                return false;
            }

            if (tdCell == null) {
                return false;
            }
            var $tdCell = $(tdCell);
            //Sean:isVisible的方法只能判断当前元素的display,如果tr隐藏的话,td判断出来还是可见的,所以这个方法不可取,改用下面的方法
            //if (!$tdCell.isVisible()) {
            if (!$tdCell.is(':visible')) {
                return false;
            }
            return this.selectMethod == 'all'
                || $tdCell.attr('editor') != null
                || $tdCell.attr('ap') != null;
        },

        /*
         * 选中dom tdCell,也就是加个黑边框,并把tdCell确保在屏幕的显示范围内
         */
        selectTDCell: function (tdCell,isStash) {
            // richer:如果填报格子有校验属性的话,校验不通过时直接返回,焦点依然在当前这个格子里
            if (this.stopCellEditing() === false) {
                return false;
            }
            if (this.writePane.isAutoStash() && isStash !== false && this.dirtyCell.length > 0) {
                this.writePane.stash();
            }

            var self = this;
            this.currentTDCell = tdCell;

            if(contentPane.options['selectedColor']) {
                $(oldSelectedCell).parent().children().removeClass("cur-tr-bg");
                oldSelectedCell = tdCell;
                $(this.currentTDCell).parent().children().addClass("cur-tr-bg");
            }
            //alex:注意,这里是fire writePane.event,不是this.event
            this.writePane.fireEvent("cellselect", this.currentTDCell);

            if (this.isSelectable(tdCell)) {
                this.dealWithBorder(tdCell);
                if (this.$glance.tdCell == tdCell) {
                    this.$glance.div.hide();
                }
            }

            // alex:让$scrollable滚动
            // bug50146 要注意冻结的情况
            var scroll = this.$scrollable;
            if (this.isFrozen()) {
                $.each(["center", "north", "west", "corner"], function (idx, item) {
                    var part = $(".frozen-" + item, self.$sheet_container);
                    if ($(tdCell).isChildAndSelfOf(part)) {
                        scroll = part;
                        return false;
                    }
                });
            }
            $(this.currentTDCell).__scroll2View__(scroll);
        },

        getTDCellBounds: function (tdCell) {
            // 取到tr,safari、chrome中td的top计算比较乱,但是tr的还是比较一致的
            var $tr = $(tdCell).parent();
            var top = $tr[0].offsetTop;
            var w = tdCell.offsetWidth;
            if (FR.Browser.isIE8()) {
                if (!$(tdCell).is(':visible')) {
                    w = 0;
                }
            }
            return {
                top: top + this.getSCOffsetTop() + tadjst,
                left: tdCell.offsetLeft + this.getSCOffsetLeft() + ladjst,
                width: w + wadjst + (FR.Browser.isIE() ? 0 : 6),
                height: tdCell.offsetHeight + hadjst
                + +(FR.Browser.isIE() ? 0 : 6)
            };
        },

        dealWithBorder: function (tdCell) {
            var bounds = this.getTDCellBounds(tdCell);
            // carl:5个。。
            this.$fD.ftop.css({top: bounds.top, left: bounds.left, width: bounds.width - 2});
            this.$fD.fleft.css({top: bounds.top + 1, left: bounds.left, height: bounds.height - 4});
            this.$fD.fbottom.css({top: bounds.top + bounds.height - 3, left: bounds.left, width: bounds.width - 2});
            this.$fD.fright.css({top: bounds.top + 1, left: bounds.left + bounds.width - 3, height: bounds.height - 4});
            this.$fD.fdot.css({top: bounds.top + bounds.height - 5, left: bounds.left + bounds.width - 5});
            this.$fD.tdCell = tdCell;
            // 要让fD的offsetParent与currentTDCell.offsetParent相同
            var $current_offset_c = $(this.currentTDCell).parents(".offset-c:eq(0)");
            if (!FR.equals(this.$fD.ftop.parents(".offset-c:eq(0)"), $current_offset_c)) {
                // carl:简单弄了,一次弄进去,不一个个判断了
                $current_offset_c.append(this.$fD.ftop);
                $current_offset_c.append(this.$fD.fleft);
                $current_offset_c.append(this.$fD.fbottom);
                $current_offset_c.append(this.$fD.fright);
                $current_offset_c.append(this.$fD.fdot);
            }
        },

        removeGlanceEditor: function (e) {
            //hiram_write 当移出时在glanceDiv中或在其他可编辑单元格中(大多数情况),就不隐藏了(其他单元格会重绘水印),减少页面重绘次数
            var $relatedTarget = $(e.relatedTarget);
            if ($relatedTarget.hasClass("glance-editor-img") || $relatedTarget.attr('editor') != null) {
                return
            }
//            if  (arget.parent().attr("id") == "glanceDiv" || $relatedTarget.attr('editor') != null) {
//                return
//            }
//            ;
            this._hideGlance();
        },

        glanceTDCell: function (tdCell) {
            var self = this;
            if (!tdCell) {
                tdCell = this.currentTDCell;
            }
            if (!isCell(tdCell) || (this.cellEditing && tdCell == this.cellEditing)) {
                return;
            }
            var $tdCell = $(tdCell);
            var editorO = $tdCell.attr('editor');
            if (editorO == null) {
                return;
            }

            editorO = FR.jsonDecode(editorO);
            // 状态保证能及时改变,所以不能取原始的信息
            var tmpWidget = contentPane.getWidgetByCell(editorO.location);
            if (tmpWidget === null || tmpWidget.options.disabled === true || tmpWidget.options.invisible === true) {
                return;
            }
            // 取到tr,safari、chrome中td的top计算比较乱,但是tr的还是比较一致的


//            this.$glance.img.show().appendTo($tdCell);
            this.$glance.tdCell = tdCell;

            if (tdCell == this.$fD.tdCell) {
//            	this._hideGlance();
                this.$glance.div.hide();
                return;
            }
            //hiram_wirte  重构显示glance
            //mylable2
//            this.$glance.top.css({top:bounds.top, left:bounds.left, width:bounds.width - 2}).show();
//            this.$glance.left.css({top:bounds.top + 1, left:bounds.left, height:bounds.height - 4}).show();
//            this.$glance.bottom.css({top:bounds.top + bounds.height - 3, left:bounds.left, width:bounds.width - 2}).show();
//            this.$glance.right.css({top:bounds.top + 1, left:bounds.left + bounds.width - 3, height:bounds.height - 4}).show();
            this._showGlance(tdCell);
            //end

            // 要让fD的offsetParent与currentTDCell.offsetParent相同
            var $current_offset_c = $(tdCell).parents(".offset-c:eq(0)");
            if (!FR.equals(this.$glance.top.parents(".offset-c:eq(0)"), $current_offset_c)) {
                // carl:简单弄了,一次弄进去,不一个个判断了
//                $current_offset_c.append(this.$glance.top);
//                $current_offset_c.append(this.$glance.left);
//                $current_offset_c.append(this.$glance.bottom);
//                $current_offset_c.append(this.$glance.right);
//                $current_offset_c.append(this.$glance.dot);
                $current_offset_c.append(this.$glance.div);
            }
        },

        /*
         * 编辑dom tdCell
         */
        editTDCell: function (tdCell) {
            //wei:去掉校验出错信息
            if ($('div.verify-error-info', FR.$view_container).length > 0) {
                $('div.verify-error-info', FR.$view_container).remove();
            }
            if (!tdCell) {
                tdCell = this.currentTDCell;
            }
            //alex:must be TD; check out if the cell in editing; check out directEdit
            if (!isCell(tdCell) || (this.cellEditing && tdCell == this.cellEditing)) {
                return;
            }
            var $tdCell = $(tdCell);
            var editorO = $tdCell.attr('editor') || $tdCell.attr('widget');
            if (editorO == null) {
                return;
            }

            editorO = FR.jsonDecode(editorO);
            // 状态保证能及时改变,所以不能取原始的信息
            var tmpWidget = contentPane.getWidgetByCell(editorO.location);
            if (tmpWidget === null || tmpWidget.options.disabled === true || tmpWidget.options.invisible === true) {
                return;
            }
            // alex:有editor属性,表明是可以编辑的,那么停止之前的编辑,开始新的编辑
            this.stopCellEditing();
            if($(this.currentTDCell).hasClass('errorCellFlag')){
                $('input',$(this.currentTDCell)).css('background','');
                $(this.currentTDCell).removeClass('errorCellFlag')
            }
            // 取到tr,safari、chrome中td的top计算比较乱,但是tr的还是比较一致的
            var $tr = $tdCell.parent();
            var top = $tr[0].offsetTop;

            var isEditor = !$tdCell.attr('widget');
            var searchEditor = this.write.getWidgetByCell(editorO.location);
            if (searchEditor) {
                this.editorEl = searchEditor;
            }
            /**
             * 直接显示控件的时候有一些特殊处理统一放到这里面去做
             */
            if (editorO.isEditable) {
                this._dealWithDirectEditCell($tdCell);
            }
            /*
             * 取得编辑器需要编辑的内容
             * 查找的顺序依次为
             * fm(formula) -> cv(Cell.Value) -> text(TD.text())
             * 如果编辑器是数字类型的话,还需要转成数值(TODO 是否可以考虑把这个类型转换放到编辑器内部去做)
             */

            var editContent = this.write.getEditContent($tdCell);

            // james:编辑器要编辑的值
            var val;
            if (typeof(editContent) == "number" || typeof(editContent) == "string") {
                val = editContent;
            } else {
                val = $.isEmptyObject(editContent) ? "" : editContent;
            }
            if (this.editorEl && this.editorEl.getType() === "number") {
                val = isNaN(val) ? '' : parseFloat(editContent);
            }

            if (this.write.isDateTypeButNotDateTimeContent(editContent, editorO)) {
                if(editorO.isEditable){
                    var fmt = $tdCell.attr('fmt');
                    if (fmt == null ) {
                        fmt = 'DMM/dd/yyyy';
                    }
                    val= FR.contentFormat(editContent.date_milliseconds, fmt);
                }else{
                    val = $tdCell.text();
                }
            }

            if (isEditor) {
                this.$editor.css({
                    top: top + this.getSCOffsetTop() + etadjst - 2,
                    left: tdCell.offsetLeft + this.getSCOffsetLeft() + eladjst - 2
                });
            } else {
                this.$editor.css({top: '-100px', left: '-100px'});
            }

            if (isEditor) {
                // 能走到这一步,这个控件必然是可编辑的,不然会在前面拦截不会生成这个editor
                this.editorEl.element.removeClass("ui-state-disabled");
                var textEditor = $(".fr-texteditor", this.editorEl.element);
                if (textEditor.length > 0 && textEditor[0].disabled === true) {
                    textEditor[0].disabled = false;
                }
                this.$editor.append(this.editorEl.element);
                /*
                 * alex:因为在编辑过程中可能导致tdCell.size改变,所以每次都要resize一下
                 */
                this.editorEl.doResize({
                    width: $tdCell.width(),
                    height: $tdCell.height()
                });
            }

            if (this.editorEl && this.editorEl.couldUsedAsEditor()) {
                // 初始化控件的阶段进行赋值不触发编辑后事件,加false参数阻止之
                this.editorEl.setValue4Write(val, false);
                // copy style
                this.editorEl.cssFrom(tdCell ,editorO.isEditable);
            }

            // 要让$editor的offsetParent与currentTDCell.offsetParent相同
            var $current_offset_c = $(this.currentTDCell).parents(".offset-c:eq(0)");
            if (!FR.equals(this.$editor.parents(".offset-c:eq(0)"), $current_offset_c)) {
                $current_offset_c.append(this.$editor);
            }

            this.$editor.show();

            if(this.editorEl && editorO.isEditable){
                if( $tdCell.context.style){
                    var editComp = this.editorEl.editComp;
                    if(editComp){
                        $(editComp).css('color', $tdCell.context.style.color || 'black');
                    }
                }
            }
            if (this.editorEl && this.editorEl.couldUsedAsEditor()) {
                var editComp = this.editorEl.editComp;
                if (editComp) {
                    if ($.isFunction(this.editorEl.selectText)) {
                        this.editorEl.selectText();
                        editComp.focus();
                    }
                    // 在没有参数界面时移动端填报页面的日期控件弹出框会被提前触发,这里导致的
                    // 移动端的离线填报比较特殊 window.mobile_browseronly不好判断
                    if (contentPane.isWriteOfflinePage) {
                        editComp.focus();
                    }

                }

                this.editorEl.startEditing();
                this.editorEl.fireEvent(FR.Events.BEFOREEDIT, tdCell, this);
            }
            this.cellEditing = tdCell;
        },

        _dealWithDirectEditCell: function ($tdCell) {
            if (!$tdCell) {
                return;
            }
            if ($tdCell.attr("fm")) {
                $tdCell.removeAttr("fm");
            }
            //bug:85087文件控件
            if (this.editorEl && $("#attach-download-id", $tdCell).length > 0) {
                this.editorEl.setVisible(true);
                $("#attach-download-id", $tdCell).remove();
            }
        },
        getWidgetCell: function (widget) {
            return $("#" + widget.options.location + "-" + this.idx + "-" + this.tableID);
        },

        // 把格子的值清空
        resetCellValue: function (widget) {
            //b:多级联动可能会报错
            var $tdCell = this.getWidgetCell(widget);
            if ($tdCell.length > 0) {
                this.fireCellValueChange($tdCell[0], "");
                this.displayTDCell($tdCell, "");
            }
        },

        stopCellEditing: function () {
            var $tdCell = $(this.currentTDCell);
            var widgetOptions = $tdCell.attr('widget');
            var editorO ;
            var isEditor = !widgetOptions;
            if(widgetOptions){
                editorO  = FR.jsonDecode(widgetOptions);
            }
            var isEditable = editorO && editorO.isEditable;//这个用来区分直接显示控件的时候该控件是否可编辑
            if (this.editorEl && this.editorEl.couldUsedAsEditor()) {
                if (!this.editorEl.isValidate()) {
                    //james:校验未通过,提示用户错误信息
                    var editor = this.editorEl;
                    //b:回复原值,现在就只有数字控件有这个操作
                    if (this.editorEl.getErrorMsg) {
                        FR.Msg.toast(this.editorEl.getErrorMsg());
                        $(this.currentTDCell).attr('title', this.editorEl.getErrorMsg());
                    } else if (this.editorEl.errorMsg) {
                        $(this.currentTDCell).attr('title', this.editorEl.errorMsg);
                    }
                    /*
                     * wei : 即使校验失败,也要记录用户输入的错误内容,不能直接将用户输入的内容清空或还原。
                     */
                    var cv = this.editorEl.getValue() || '';
                    if (editor.recoveryValue) {
                        editor.recoveryValue();
                        if (editor.validateCss) {
                            editor.validateCss();
                        }
                    }
                    if (isEditor) {
                        this.$editor.hide();
                        this.editorEl.element.detach();
                        this.displayTDCell(this.currentTDCell, this.editorEl.getValue());
                    }

                    if(isEditable){

                        this.setEditableWidgetDisplayValue(editorO, cv ,$tdCell);

                    }
                    this.fireCellValueChange(this.currentTDCell, cv);
                    /*
                     *这边直接显示控件且控件可编辑的时候不需要保留焦点在当前格子 return true
                     */
                    if(isEditable && this.editorEl.editComp){
                        this.editorEl.editComp.addClass('dirty');
                    }
                    this.editorEl = null;
                    this.cellEditing = null;
                    return isEditable || false;

                } else {
                    var cellId = (this.currentTDCell.id.split('-'))[0];
                    var reportIndex = (this.currentTDCell.id.split('-'))[1];
                    var verifyErrorContainer = $('div.verify-error-container', FR.$view_container);
                    var verifyButton = $('button.x-emb-verify');
                    if (verifyErrorContainer.length > 0 && $('td#' + cellId + '-' + reportIndex, verifyErrorContainer).length > 0) {
                        $('td#' + cellId + '-' + reportIndex, verifyErrorContainer).remove();
                        var errornum = parseInt($('div.verify-error-number', verifyButton).text());
                        if (errornum - 1 > 0) {
                            $('div.verify-error-number', verifyButton).text(errornum - 1);
                        } else {
                            $('div.verify-error-number', verifyButton).remove();
                        }
                        if ($('td:visible', verifyErrorContainer).length === 0) {
                            $('div.verify-error-messages:visible', verifyErrorContainer).parent().remove();
                        }
                        if ($('td.verify-item-idx' + reportIndex, verifyErrorContainer).length === 0) {
                            var tabPane = contentPane.$contentPane.data('TabPane');
                            if (tabPane) {
                                for (var i = 0; i < tabPane.tabBtns.length; i++) {
                                    tabPane.tabBtns[i].setValidState(true);
                                }
                            }
                        }
                    }
                }
                var result, fired = false;
                var isDirty = this.editorEl.isDirty();
                if (this.writePane.fireStopEditOnChange === false) {
                    result = this.editorEl.fireEvent(FR.Events.STOPEDIT, this.currentTDCell, this);
                    fired = true;
                }
                if (isDirty || isEditable) {
                    // richer:做这个判断是为了删除行列以后不再纠缠
                    var cell = this.getWidgetCell(this.editorEl);
                    if (cell.hasClass("del")) {
                        return false;
                    } else {
                        if (!fired) {
                            result = this.editorEl.fireEvent(FR.Events.STOPEDIT, this.currentTDCell, this);
                        }
                        // stopedit之后再取值,有可能stopedit事件中会有setValue操作
                        var value = this.editorEl.getValue();
                        var cv = value;
                        if (!result) {
                            return false;
                        }
                        if (cv == null) {//不能用!cv判断,不然cv=0的时候也返回TRUE的
                            cv = '';//james:如果没有返回值怎么办呢?先返回一个空字符串吧
                        }

                        var $tr = $(this.currentTDCell).parent();
                        var oriHeight = $tr.isVisible() ? $tr.height() : 0;

                        if (isEditor) {
                            if (this.editorEl.options.passwordText) {
                                // 密码控件统一显示*
                                value = value.replace(/[0-9a-zA-Z_]/g, '*');
                            }
                            this.displayTDCell(this.currentTDCell, value);
                        }
                        if(isEditable) {
                            this.setEditableWidgetDisplayValue(editorO, cv, $tdCell);
                        }
                        if(isDirty){
                            if(isEditable){
                                //zack:这边触发valuechange的时候把fm属性带过去,不然的话单元格联动关系在被动单元格被编辑之后就会失效了(不带过去的话方法中慧移除fm属性)
                                this.fireCellValueChange(this.currentTDCell, cv ,$(this.currentTDCell).attr('fm'));
                            }else{
                                // james:说明是下拉框等有value和text属性的返回值
                                // alex:这里displayTDCell的参数是cv而不是cv.text,因为里面会做dict处理
                                // richer:加一个参数选择displayTDCell的事cv还是cv.text,因为用dict的话需要很多多余的操作步骤,这样相当于提供一个统一的设置
                                this.fireCellValueChange(this.currentTDCell, cv );
                            }

                            FR.modifyRowHeightAfterContentChange($tr, oriHeight);

                            this.resizeWidgetsAfterTrChange($tr, oriHeight, isEditable);
                        }
                    }
                }
                $(this.currentTDCell).removeAttr('title');
                if (isEditor) {
                    this.editorEl.stopEditing();
                    this.$editor.hide();
                    this.editorEl.element.detach();
                }
            } else {
                //clear the hidden editorEls in editorDIV since editorEl.destroy() may pass focus to window
                //            clearDom(this.$editor.dom);
            }
            this.editorEl = null;
            this.cellEditing = null;

            if (this.isSelectable(this.currentTDCell)) {
                //还原wei的,原来不知道,这里如果格子大小变了的话(.html(), 不好检测),就需要重设边框了。
                this.dealWithBorder(this.currentTDCell);
            }


            return true;
        },
        resizeWidgetsAfterTrChange: function($tr, oriHeight, isEditable){
            if(!isEditable || $tr.height() === oriHeight){
                return;
            }
            if ($tr.length === 0 || $tr[0].id === null || $tr[0].id == undefined) {
                return;
            }
            var index = $tr[0].id.substring($tr[0].id.indexOf('-') + 1, $tr[0].id.lastIndexOf('-'));
            var $trs = $("tr[tridx='" + index + "']" ,"div.content-container");
            var self = this;
            if ($trs && $trs.length > 0) {
                for (var i = 0; i < $trs.length; i++) {
                    var $tmpTr = $trs.eq(i);
                    if ($tmpTr.isVisible()) {
                        $tmpTr.find('td').each(function(){
                            var editorO =$(this).attr('editor') || $(this).attr('widget');
                            var $editorEl;
                            if (editorO) {
                                editorO = FR.jsonDecode(editorO);
                                if (self.write.location_widgets && self.write.location_widgets[editorO.location]) {
                                    $editorEl = $(self.write.location_widgets[editorO.location]);
                                }
                            }
                            if(FR.isEmpty($editorEl)){
                                return;
                            }
                            var give={
                                height : $tmpTr.height() - 1,//这边减去编辑框的边框
                                width : $(this).width() ||  $(this).attr("widgetWidth")
                            };
                            $editorEl[0].doResize(give);
                        });
                    }
                }
            }
        },
        setEditableWidgetDisplayValue : function (editorO, cv, $tdCell, value){
            if (editorO && this.write.location_widgets && this.write.location_widgets[editorO.location]) {
                var cellWidget = this.write.location_widgets[editorO.location];
                //bug84620这边设置的其实是显示值.实际值是通过firecellvaluechange设置的
                cellWidget.setText(this.formatCellValue($tdCell, cv, value));
                if (editorO.isEditable && cellWidget.editComp) {
                    cellWidget.editComp.addClass('dirty');
                    //zack:如果单元格没有值,且有水印,恢复水印的颜色
                    if(cv === ''&& editorO.watermark){
                        $(cellWidget.editComp).css('color',$tdCell.getwatermarkcolor())
                    }
                }

            }
        },
        /**
         *
         * @param col
         * @param row
         * @returns {jQuery}
         * @private
         */
         _get$TDCell: function (col, row) {
            if (row != null) {
                col = {col: col, row: row};
            }
            if (typeof col == 'object') {
                col = FR.columnRow2CellStr(col);
            }

            // alex:太诡异了,从全局取居然比从this.$table中取要快~~ TODO to find out why~
            // carl:不能全局,否则就搜到parameterPane那去了
            // denny: tracker@953, 全局直接id效率高的原因是可以直接getElementById,否则需要遍历
            var cell = $('#' + col + "-" + this.idx + "-" + this.tableID);
            if (cell == null) {
                cell = $('td[position*=' + '\'' + col + "-" + this.idx + '\']', this.$table);
            }

            return cell;
        },

        /**
         * 获取某个单元格td的jquery对象
         * e.g. 获取当前sheet的第三行第二列的格子 contentPane.curLGP.getTDCell(1,2)
         * @param col
         * @param row
         * @returns {*}
         */
        getTDCell: function (col, row) { //alex:可以传一个参数{col:1,row:2}或"A1",也可以传两个参数1,2
            var $res = this._get$TDCell(col, row);
            if ($res != null && $res.length > 0) {
                return $res[0];
            }

            return null;
        },

        /**
         * 移动选中格子的黑框
         *
         *     @exmaple
         *     contentPane.curLGP.moveTDCell(1);//向上移动黑框
         *
         * @param direction
         */
        moveTDCell: function (direction) {
            if (this.currentTDCell == null) {
                return;
            }
            // alex:如果正在移动,直接return(报表大了,遍历也是挺费时的)
            if (this.__moving__ === true) {
                return;
            }
            this.__moving__ = true;

            var self = this;
            if (this.lastRow == null) {
                var trs = this.$table.find('tbody:eq(0)').children().filter('tr[id]');
                var lastTR = trs.eq(trs.length - 1)[0];
                this.lastRow = lastTR && lastTR.id ? parseInt(lastTR.id.split("-")[1]) : 0;
            }
            if (this.lastCol == null) {
                this.lastCol = 0;
                this.$table.find("tbody:eq(0)").children().each(function () {
                    var tds = $(this).children().filter('td[id]');
                    var lastTd = tds.eq(tds.length - 1)[0];
                    if (lastTd && lastTd.id) {
                        self.lastCol = Math.max(self.lastCol, FR.id2ColumnRow(lastTd.id).col);
                    }
                });
            }

            var cr = FR.id2ColumnRow(this.currentTDCell.id);
            var row = cr.row;
            var column = cr.col;

            var tc = column;
            var tr = row;
            var tdCell = null;

            switch (direction) {
                case LEFT:
                    while (!this.isWeakSelectable(tdCell) && tc >= 1) {
                        tc--;
                        tdCell = this.getTDCell(tc, tr);
                    }
                    break;

                case RIGHT:
                    tc += this.currentTDCell.colSpan - 1;
                    tdCell = this._moveRight(tdCell, tc, tr);
                    break;
                case UP:
                    while (!this.isWeakSelectable(tdCell) && tr >= 1) {
                        tr--;
                        tdCell = this.getTDCell(tc, tr);
                    }
                    break;

                case DOWN:
                    tr += this.currentTDCell.rowSpan - 1;
                    tdCell = this._moveDown(tdCell, tc, tr);
                    break;
            }
            if (this.isWeakSelectable(tdCell)) {
                this.selectTDCell(tdCell);
                if (this.writePane.editOnMove || this.isEditableWidget(tdCell)) {
                    this.editTDCell(tdCell);
                }
            }

            this.__moving__ = false;
        },

        _moveRight: function (tdCell, col, row) {
            var startCol = col, startRow = row;
            while (!this.isWeakSelectable(tdCell)) {
                // move right
                if (col < this.lastCol) {
                    col++;
                    // move down
                } else if (row < this.lastRow) {
                    col = 0;
                    row++;
                    // move to start
                } else {
                    col = 0;
                    row = 0;
                }
                if (col == startCol && row == startRow) {
                    return null;
                }
                tdCell = this.getTDCell(col, row);
            }
            return tdCell;
        },

        _moveDown: function (tdCell, col, row) {
            var startCol = col, startRow = row;
            while (!this.isWeakSelectable(tdCell)) {
                // move down
                if (row < this.lastRow) {
                    row++;
                    // move top
                } else if (col < this.lastCol) {
                    row = 0;
                    col++;
                    // move to start
                } else {
                    col = 0;
                    row = 0;
                }
                if (col == startCol && row == startRow) {
                    return null;
                }
                tdCell = this.getTDCell(col, row);
            }
            return tdCell;
        },

        previewAttachment: function (target, attach) {
            var self = this;

            function download(e) {
                window.open(FR.servletURL + "?op=fr_attach&cmd=ah_download&id="
                    + e.data);
                e.stopPropagation();
            }

            function addDownloadAllButton(target, attachid, isImage) {
                if ($(".ui-state-enabled", $target)) {
                    $(".ui-state-enabled", $target).hide();
                }
                var top = target.parent()[0].offsetTop;
                var width = parseInt($(target[0]).attr('widgetwidth'));
                var $button = $('<div class = "fr-fileupload-download-all">').appendTo(target);
                if (isImage) {
                    $button.css({
                        top: top + self.getSCOffsetTop() + etadjst - 2,
                        left: target[0].offsetLeft + self.getSCOffsetLeft()
                        + eladjst - 18 + width
                    })
                }
                $button.click(function (e) {
                    window.open(FR.servletURL
                        + "?op=fr_attach&cmd=ah_download&id=" + attachid);
                    e.stopPropagation();
                });
            }

            FR.lastTarget = target;
            var $target = $(target);
            $target.css("background-image", "");
            var showImage = false;
            if (attach.attach_type == 'image') {
                var id = $target[0].id;
                if (id && id.split("-").length > 0) {
                    var cr = id.split("-")[0];
                    var widget = contentPane.getWidgetByCell(cr);
                    if (widget && $.isFunction(widget.isShowViewImage)) {
                        showImage = widget.isShowViewImage();
                    } else {
                        showImage = true;
                    }
                }
            }
            if (showImage) {
                // 多文件的时候attach是数组 单文件并且是图片的时候默认显示图片背景
                var im_url = FR.servletURL + '?op=fr_attach&cmd=ah_image&id=' + attach.attach_id;
                $target.css('background', 'url(' + im_url + ") 0 0 no-repeat transparent");
                $target.css("cursor", "default").unbind("click", download);
                addDownloadAllButton($target, attach.attach_id, true);
            } else {
                if ($("#attach-download-id", $target).length > 0) {
                    $("#attach-download-id", $target).remove();
                }
                var table = $("<table cellspacing='0' >")
                    .appendTo(($("<div id='attach-download-id'/>")
                        .appendTo($target)));
                var colGroup = $('<colgroup/>').appendTo(table);
                var w = $(target).width(), h = $(target).height();
                var wb = 18;
                colGroup.append($('<col col="0"/>').width(w - wb))
                    .append($('<col col="1"/>').width(wb));
                var trr = $("<tr />").height(h)
                    .appendTo($("<tbody>")
                        .appendTo(table));
                var tdd = $("<td />").appendTo(trr);
                var tdd2 = $("<td style='vertical-align:top'>").appendTo(trr);
                if ($('.attach-download-div,.fr-fileupload-download-all',
                        $target).length !== 0) {
                    $('.attach-download-div,.fr-fileupload-download-all',
                        $target).remove();
                }
                var td = $("<td>")
                    .appendTo($("<tr>")
                        .appendTo($("<tbody>")
                            .appendTo(($("<table cellspacing='0' >")
                                .appendTo(($("<div class = 'attach-download-div'>").width(w - wb)
                                    .appendTo(tdd)))))));
                if (FR.isArray(attach)) {
                    var id = "";
                    for (var i = 0; i < attach.length; i++) {
                        var dup = 0;
                        var tempName = attach[i].filename;
                        for (var j = 0; j < i; j++) {
                            if (attach[i].filename === attach[j].filename) {
                                dup++;
                            }
                        }
                        if (dup > 0) {
                            tempName = FR.lengthenFileName(attach[i].filename, "(" + dup + ")");
                        }
                        td.append($("<span class='fr-attach-download'>"
                            + tempName + " </span>").bind(
                            'click', attach[i].attach_id, download));
                        id += attach[i].attach_id;
                        if (i != attach.length - 1) {
                            id += ".";
                        }
                    }
                    addDownloadAllButton(tdd2, id);
                } else {
                    td.append($("<span class='fr-attach-download'>"
                        + attach.filename + " </span>").bind('click',
                        attach.attach_id, download));
                }
                if (FR.Browser.isIE()) {
                    $(".fr-attach-download").css({'font-size': '12px'});
                }
            }
        },
        /**
         * 把值显示在TD里面
         *
         * cv 可以是 {text, value},就直接显示text, 也可以是一段字符串,则根据dict的有无来判断是否要用dict处理一下
         */
        displayTDCell: function (tdCell, cv, presentValue) {
            var $tdCell = $(tdCell);
            //b:widget状态只需显示控件
            if (this.showAsWidget($tdCell)) {
                return;
            }
            // carl : 隐藏的单元格不显示
            if ($tdCell.is('.cehide')) {
                return;
            }

            // BUG0001372 填报中下拉框选值无法显示正确
            if (FR.isArray(cv)) {// james:如果cv是Array的话,那么目前的情况就是复选框会出现这样的结果,其他的编辑器目前全部是只返回一个值
                var content = this.calArrayTypeCV2Content(cv, $tdCell);

                this.formatAndSetContent(content, $tdCell);

            } else {
                // alex:如果有present,要到服务器上去问一下,present之后是什么东西

                cv = this.calNormalTypeCV2Content(cv, $tdCell, presentValue)

                this.formatAndSetContent(cv, $tdCell)

            }
        },

        calArrayTypeCV2Content : function(cv, $tdCell){
            var content = '';
            if (cv[0] && cv[0].attach_id != null && cv[0].attach_type != null) {
                content = cv;
            } else {
                var delimiter = ',';
                //wei : 树  // 复选树
                if (cv[0] instanceof Array) {
                    delimiter = ';';
                }
                if ($tdCell.is('.presentable')) {   //august:做形态判断
                    // shoc 到这里的可能是下拉复选框 复选框组 单选树 复选树, 树的值要做整体处理,不然如果用公式形态treelayer的话不好搞
                    var editorAttr = FR.jsonDecode($tdCell.attr('editor'));
                    if (editorAttr && editorAttr.type == "treecombobox" && !editorAttr.mutiSelection) {
                        content = this.present($tdCell, cv);
                    } else {
                        for (var i = 0; i < cv.length; i++) {
                            if (i !== 0) {
                                content += delimiter;
                            }
                            content += this.present($tdCell, cv[i]);
                        }
                    }
                }
                else {
                    for (var i = 0; i < cv.length; i++) {
                        if (i !== 0) {
                            content += delimiter;
                        }
                        content += cv[i];
                    }
                }
            }
            return content;
        },

        calNormalTypeCV2Content : function(cv, $tdCell, presentValue){
            if ($tdCell.is('.presentable')) {
                // 假如已经给计算了的,就直接用不需要再去服务器算了
                return presentValue ? presentValue : this.present($tdCell, cv);
            }
            return cv;
        },
        /**
         * 格式化单元格值
         * @param dp 单元格值
         * @param $tdCell 单元格
         * @returns {*} 格式化结果
         */
        formatContent : function (dp , $tdCell){
            var self = this;
            var editorO = $tdCell.attr('editor') || $tdCell.attr('widget');
            var $editorEl;
            if (editorO) {
                //设置单元格值后还需要设置控件值。如果控件已经初始化了,调到其setValue方法,否则改变下editorO.value属性
                editorO = FR.jsonDecode(editorO);
                if (self.write.location_widgets && self.write.location_widgets[editorO.location]) {
                    $editorEl = $(self.write.location_widgets[editorO.location]);
                }
            }
            if(FR.isEmpty($editorEl)){
                return dp;
            }
            var fmt = $tdCell.attr('fmt');
            if (fmt == null && (dp instanceof Date || $tdCell.attr('editor') == "date")) {
                fmt = 'DMM/dd/yyyy';
            }
            var self = this;
            if (typeof dp == 'string') {
                if (dp && dp.indexOf('\n') != -1) {
                    dp.replace(/ /gi, "&nbsp;");
                }
                dp.replace(/\n/gi, "<br/>");
            }

            if (!FR.isEmpty(dp) && dp.src != null) {
                var url = dp.src;
                $tdCell.html(null);
                return $("<img src='" + url + "'/>").css('border-width', 0);// ie 强制0
            }

            // alex:{attach_type, attach_id},表示一个附件
            else if (!FR.isEmpty(dp) && dp.attach_type != null && dp.attach_id != null) {
                self.previewAttachment($tdCell, dp);
//                    $tdCell.empty();
            }
            //wei : 对多文件的处理
            else if (FR.isArray(dp) && dp.length > 0 && dp[0].attach_type != null && dp[0].attach_id != null) {
                self.previewAttachment($tdCell, dp);
            } else {
                if ($tdCell.is('.celink')) {
                    return FR.contentFormat(dp, fmt);
                } else {
                    // richer:这里涉及到换行符,要把"\n"转换为"<br/>"所以用html()
                    var content = FR.contentFormat(dp, fmt);
                    //wei : 水印显示在单元格上
                    var oldTdCellColor = $tdCell.css('color');
                    FR.$defaultImport('/com/fr/web/core/js/jquery.watermark.js', 'js');
                    if (content == '' && editorO.watermark) {
                        $editorEl.addClass('watermarkCell');
                        return content;
                    } else {
                        $editorEl.removeClass('watermarkCell');
                        if ($tdCell.attr("showashtml") === "true" || content.indexOf("<br/>") !== -1) {
                            return content;

                        } else {
                            if (editorO.type == 'text') {
                                return content;
                            } else {
                                return content;
                            }
                        }
                        // ie标准是 "rgb(204, 204, 204)" ie杂项是"rgb(204,204,204)"
                        if (oldTdCellColor && (oldTdCellColor == $tdCell.getwatermarkcolor()
                            || oldTdCellColor.replace(/ /g, '') == $tdCell.getwatermarkcolor().replace(/ /g, ''))) {
                            $editorEl.css('color', '');
                        } else {
                            $editorEl.css('color', oldTdCellColor);
                        }
                    }
                }
            }
        },
        formatAndSetContent : function (dp , $tdCell ) {
            var self = this;
            if (typeof dp == 'string') {
                if (dp && dp.indexOf('\n') != -1) {
                    dp = dp.replace(/ /gi, "&nbsp;");
                }
                dp = dp.replace(/\n/gi, "<br/>");
            }
            // alex:再用格式处理显示值
            var fmt = $tdCell.attr('fmt');
            if (fmt == null && (dp instanceof Date || $tdCell.attr('editor') == "date")) {
                fmt = 'DMM/dd/yyyy';
            }
            // jim:41954 自定义公式生成的图片,在填报重新计算时,显示新的图片
            if (!FR.isEmpty(dp) && dp.src != null) {
                var url = dp.src;
                $tdCell.html(null);
                var $image = $("<img src='" + url + "'/>").css('border-width', 0);// ie 强制0
                $image.appendTo($tdCell);
            }

            // alex:{attach_type, attach_id},表示一个附件
            else if (!FR.isEmpty(dp) && dp.attach_type != null && dp.attach_id != null) {
                self.previewAttachment($tdCell, dp);
//                    $tdCell.empty();
            }
            //wei : 对多文件的处理
            else if (FR.isArray(dp) && dp.length > 0 && dp[0].attach_type != null && dp[0].attach_id != null) {
                self.previewAttachment($tdCell, dp);
            } else {
                var content = FR.contentFormat(dp, fmt);
                if ($tdCell.is('.celink')) {
                    var link_span = $('.linkspan', $tdCell)[0];
                    if (link_span) {
                        $(link_span).html(content);
                    }else{
                        //80822 CellHtmlWriter里只有纯色和无背景的时候, 写了linkspan
                        $tdCell.html(content);
                    }
                } else {
                    // richer:这里涉及到换行符,要把"\n"转换为"<br/>"所以用html()
                    //wei : 水印显示在单元格上
                    var editor = FR.jsonDecode($tdCell.attr('editor'));
                    var oldTdCellColor = $tdCell.css('color');
                    FR.$defaultImport('/com/fr/web/core/js/jquery.watermark.js', 'js');
                    if (content == '' && editor.watermark) {
                        $tdCell.text(editor.watermark).css('color', $tdCell.getwatermarkcolor());
                        $tdCell.addClass('watermarkCell');
                    } else {
                        $tdCell.removeClass('watermarkCell');
                        if ($tdCell.attr("showashtml") === "true" || content.indexOf("<br/>") !== -1) {
                            $tdCell.html(content);
                        } else {
                            if (editor.type == 'text') {
                                content = content.replace(/ /gi, "&nbsp;");
                                $tdCell.html(content);
                            } else {
                                $tdCell.text(content);
                            }
                        }
                        // ie标准是 "rgb(204, 204, 204)" ie杂项是"rgb(204,204,204)"
                        if (oldTdCellColor && (oldTdCellColor == $tdCell.getwatermarkcolor()
                            || oldTdCellColor.replace(/ /g, '') == $tdCell.getwatermarkcolor().replace(/ /g, ''))) {
                            $tdCell.css('color', '');
                        } else {
                            $tdCell.css('color', oldTdCellColor);
                        }
                    }
                }
            }
        },
        /**
         * alex:作形态处理
         */
        present: function ($tdCell, cv) {
            // richer:记录关联格子信息
            var depO = {};
            var dep = FR.jsonDecode($tdCell.attr("presentDep"));
            var self = this;
            if (dep) {
                $.each(dep, function (i, item) {
                    if(item === '$$$'){
                        return
                    }
                    var cell = item.toUpperCase().startWith("$") ? item.toUpperCase().substring(1) : item.toUpperCase();
                    var cv = self.getCellValue(cell);
                    //bug77772,cell不一定是单元格(=有可能就是参数$aaaaa),如果不是单元格再走一下控件。
                    if(!FR.isEmpty(cv)){
                        depO[cell] = cv;
                    }else{
                        var widget = self.write.getWidgetByName(cell);
                        if(widget && widget.getValue()){
                            depO[cell] = widget.getValue();
                        }
                    }

                });
            }
            FR.ajax({
                url: FR.servletURL + "?sessionID=" + this.writePane.currentSessionID,
                // james:BUG0003031
                // jim:bug59907 判断为空用isEmpty 防止数字0
                data: $.extend({
                    op: "fr_write",
                    cmd: 'write_present',
                    value: FR.isEmpty(cv) ? "" : cv,
                    dependence: depO}, FR.id2Location($tdCell.attr("id"))),
                async: false,
                complete: function (res, status) {
                    if (status == 'success') {
                        cv = FR.jsonDecode(res.responseText);
                    }
                }
            });

            // jsonDecode在705被改成可能返回空Object web端present怎么也不该返回这个东西
            // $.isEmptyObject("2")结果为true。。。
            return (typeof cv == 'object' && $.isEmptyObject(cv)) ? "" : cv;
        },

        /**
         * 得到单元格的行号
         * API的提供的行列都从1开始
         *
         * @param td
         * @return {number}
         */
        getTDRow: function (td) {
            var cr = FR.id2ColumnRow($(td).attr('id'));
            return cr ? (cr.row + 1) : -1;
        },

        /**
         * 得到单元格的列号
         *
         * @param td
         * @return {number}
         */
        getTDCol: function (td) {
            var cr = FR.id2ColumnRow($(td).attr('id'));
            return cr ? (cr.col + 1) : -1;
        },

        /**
         * 隐藏选中的黑框
         *
         *     @example
         *     contentPane.curLGP.hideSelectFrame();
         */
        hideSelectFrame: function () {
            this.$fD.ftop.css('display', 'none');
            this.$fD.fleft.css('display', 'none');
            this.$fD.fbottom.css('display', 'none');
            this.$fD.fright.css('display', 'none');
            this.$fD.fdot.css('display', 'none');
        }
    }
}());

//RowHelper提供插入行时的一些方法
FR.WLGP.RowHelper = {};
FR.WLGP.RowHelper.compare = function (colRow, row) {
    if (colRow.row > row) {
        return 1;
    }
    if (colRow.row < row) {
        return -1;
    }
    if (colRow.row == row) {
        return 0;
    }
};
FR.WLGP.RowHelper.add4CellStr = function (cellStr, len) {
    var colRow = FR.cellStr2ColumnRow(cellStr);
    colRow.row = colRow.row + len;
    return FR.columnRow2CellStr(colRow);
};
FR.WLGP.RowHelper.compare4CellStr = function (cellStr, row) {
    var colRow = FR.cellStr2ColumnRow(cellStr);
    return FR.WLGP.RowHelper.compare(colRow, row);
};
FR.WLGP.RowHelper.add4TrId = function (id, len) {
    var idArray = id.split("-");
    idArray[1] = len + parseInt(idArray[1]);
    return idArray.join("-");
};


$.extend(FR, {
    /*
     * 设置TDCell的值
     */
    setCellValue: function (tdCell, val) {
        if (val instanceof Date) {
            val = {date_milliseconds: val.getTime()}
        }
        $(tdCell).attr('cv', FR.jsonEncode(val));
    },

    /*
     * 获取TDCell的值
     */
    getCellValue: function (tdCell) {
        var json_cv = $(tdCell).attr('cv');
        // richer:没有值的时候直接返回空字符串,不要返回null
        if (json_cv == null) {
            return "";
        } else {
            return FR.jsonDecode(json_cv);
        }
    },

    /**
     * 调整对应行的行高,为冻结服务
     */
    modifyRowHeightAfterContentChange: function ($tr, oriHeight) {
        //不同table中相同id的元素用jquery取的话,chrome能取全部,ie67只能取第一个
//        var $trs = $("tr #"+$tr[0].id);
        if ($tr.length === 0 || $tr[0].id === null || $tr[0].id == undefined) {
            return;
        }
        var currentTrHeight = $tr.height();
        if(currentTrHeight === oriHeight){
            return;
        }
        var index = $tr[0].id.substring($tr[0].id.indexOf('-') + 1, $tr[0].id.lastIndexOf('-'));
        var $trs = $("tr [tridx='" + index + "']");
        var dif = ($tr.isVisible() ? $tr.height() : 0) - oriHeight;
        var hasVerticalBorder = function ($tr) {
            for (var i = 0; i < $tr.children().length; i++) {
                if ($tr.children().eq(i).border().top + $tr.children().eq(i).border().bottom > 0) {
                    return true;
                }
            }
        }
        if ($trs && $trs.length > 1) {
            for (var i = 0; i < $trs.length; i++) {
                var tmpTr = $trs.eq(i);
                if (!tmpTr.isChildAndSelfOf($tr) && tmpTr.isVisible() && tmpTr.height() != currentTrHeight) {
                    if (FR.Browser.isIE7Before()
                        && hasVerticalBorder($tr) && hasVerticalBorder(tmpTr)) {
                        dif = dif - 1;
                    }
                    tmpTr.height(tmpTr.height() + dif);
                }
            }
        }
    }
});