(function ($) {

    /**
     * 带额外点击按钮的控件,这是一个抽象类,所有带有下拉按钮的控件的父类。
     * @class FR.TriggerEditor
     * @extends FR.BaseEditor
     * @abstract
     *
     * @cfg {Number} [width=100] 控件的宽度
     * @cfg {Number} [height=22] 控件的高度
     */
    FR.TriggerEditor = FR.extend(FR.EditCompBaseEditor, /**@class FR.TriggerEditor*/{
        /**
         * @protected
         */
        _defaultConfig: function () {
            return $.extend(
                FR.TriggerEditor.superclass._defaultConfig.apply(), {
                    baseCls: "fr-trigger-editor",
                    btn_up: "fr-trigger-btn-up",
                    btn_down: "fr-trigger-btn-down",
                    btn_over:"fr-trigger-btn-over",
                    text_focus:"fr-trigger-text-focus",
                    width: 100,
                    height: 22
                });
        },
        /**
         * @protected
         */
        _init: function () {
            FR.TriggerEditor.superclass._init.apply(this, arguments);
            this.initData();
            this.addContent2Element();
            this.validateCss();
        },

        /**
         * 添加内容
         */
        addContent2Element: function () {
            var o = this.options;
            this.element.addClass(o.baseCls);
            this.triggerTextComp = this.createTextComp();
            //左部-文本编辑框组件
            this._createTextComp();
            //控件尺寸调整
            o.width = (o.width > -1) ? o.width : this.triggerTextComp.width();
            o.height = (o.height > -1) ? o.height : this.triggerTextComp.height();
            //右部-下拉触发按钮组件
            this._createTriggerBtn();
            //下拉触发按钮组件样式
            this.arrow = $('<div/>').addClass('fr-trigger-center');
            this._createStyle4TriggerBtn();
            var bw = $.support.boxModel ? this.btn.outerWidth() : this.btn.width();
            //zack:这边8.0直接显示控件的时候ie678下btn.width()可能会出现
            // 结果为16的情况估计是扣除了边框了小于18的时候强制改成18,因为实际占用的宽度就是18
            this.btnWidth = bw > 18 ? bw : 18 + this.fixbtnWidthValue();
            this.doResize(o);
            //数据加载只在下拉时触发
            if (o.value || o.value === 0) {
                this._dealValueWithEvents(o.value, false);
            }
            //直接显示控件的时候,初始化的时候显示显示值。
            if(o.isEditable){
                this.dealWithDisplayValue(o.showValue);
            }
            //初始化下拉表容器
            this._initViewContainer();
        },
        createTextComp : function(){
            return $("<div class='fr-trigger-text'></div>")
                .appendTo(this.element);
        },

        /**
         * 获取下拉箭头图标的高度
         * @returns {number}
         */
        getArrowIconHeight : function(){
            return 7;
        },
        /**
         * 生成文本编辑组件
         * @private
         */
        _createTextComp: function () {
            var o = this.options, self = this;
            this.editComp = $("<input type='text'/>").addClass('fr-trigger-texteditor')
                .appendTo(this.triggerTextComp);
            this.editComp.blur(function () {
                self.editComp.removeClass('fr-trigger-texteditor-focus');
                self.triggerTextComp.removeClass(self.options.text_focus);
                self._editCompBlur();
                if (self._canCancelSearch() && !FR.isEmpty(self.searchText) && self.searchCancel !== false) {
                    self.searchCancel = true;
                    self.editComp.val("");
                    self.setValue(self.originalValue, false);
                } else {
                    // 如果焦点离开,同时下拉列表展开了,说明是onTriggerClick,此时不应触发编辑结束事件
                    if (jQuery.isFunction(self.isExpanded) && self.isExpanded()) {
                        return;
                    }
                    // 点击列表的选项会失焦一下,这时不应触发编辑结束事件
                    if (self.editComp && self.editComp[0] == document.activeElement) {
                        return;
                    }
                    self._editCompBlurValidValue();

                    if (!self.options.write) {
                        self.fireEvent(FR.Events.STOPEDIT);
                    }
                }
            }).focus(function () {
                self.editComp.addClass('fr-trigger-texteditor-focus');
                self.triggerTextComp.addClass(self.options.text_focus);
                if (self.originalValue == null) {
                    self.originalValue = self.getValue();
                }
                if (!self.options.write) {
                    self.fireEvent(FR.Events.BEFOREEDIT);
                }
                self._editCompFocus();
            });
            if (o.fontSize) {
                this.editComp.css('font-size', o.fontSize);
            }
            if (o.directEdit !== true) {
                this.editComp.attr('readonly', true);
            }
            if (o.disabled === true) {
                this.editComp.attr("disabled", "disabled");
            }
            this.editComp.__bind__('keydown', this, this._onKeyDown);
        },
        /**
         * 生成下拉触发按钮组件
         * @private
         */
        _createTriggerBtn: function () {
            var self = this;
            var triggerFn = this.onTriggerClick.createDelegate(this);

            this.btn = $("<div/>").addClass(self.options.btn_up)
                .appendTo(this.element);
            var M = {
                onMouSeenter: function (e) {
                    if (!self.options.disabled) {
                        self.btn.switchClass(self.options.btn_over);
                    }
                },
                onMouseLeave: function (e) {
                    if (!self.options.disabled) {
                        self.btn.switchClass(self.options.btn_up);
                    }
                },
                onMouseDown: function (e) {
                    if (!self.options.disabled) {
                        self.btn.switchClass(self.options.btn_down);
                    }
                },
                onMouseUp: function (e) {
                    if (!self.options.disabled) {
                        self.btn.switchClass(self.options.btn_over);
                        triggerFn();
                    }
                }
            };
            this.btn.mouseenter(M.onMouSeenter).mouseleave(M.onMouseLeave)
                .mouseup(M.onMouseUp).mousedown(M.onMouseDown);
        },

        /**
         * 下拉列表是否展开
         * @returns {Boolean} 返回是,则表示展开状态;否则为收起状态
         */
        isExpanded: function () {
            return this.$view && this.$view.is(":visible");
        },

        /**
         * 鼠标下拉框外点击,收起下拉框
         * @param {Object} e 鼠标事件
         */
        collapseIf: function (e) {
            var self = e.data;
            //iframe嵌入的情况下点击滚动条有时候会出现pageX为null的情况
            if (e.pageX == null ||
                ((e.pageX < self.$view.offset().left || e.pageX > self.$view.offset().left + self.$view.width()
                || e.pageY < self.$view.offset().top || e.pageY > self.$view.offset().top + self.$view.height())
                && (e.pageX < self.btn.offset().left || e.pageX > self.btn.offset().left + self.btn[0].offsetWidth
                || e.pageY < self.btn.offset().top || e.pageY > self.btn.offset().top + self.btn[0].offsetHeight))) {
                self.collapse();
            }
        },

        /**
         * 收起下拉列表
         */
        collapse: function () {
            if (!this.isExpanded()) {
                return;
            }
            this.$view.hide();
            $(document).unbind('mousedown', this.collapseIf).unbind('mousewheel', this.collapseIf);
            if (this.options.write && this.options.write.lgp) {
                this.options.write.lgp.$container.unbind('scroll', this.collapseIf);
            }
            // 表单文本框获取焦点会触发编辑前事件 这时候focus有点问题
            // 但是表单中控件的编辑结束事件是通过焦点离开触发的 不聚焦没法触发
            this.editComp.focus();
            this.focusIndex = undefined;
            this.fireEvent(FR.Events.COLLAPSE);
        },

        /**
         * 能否取消搜索
         * @returns {Boolean} 判断是否可以取消搜索
         * @protected
         */
        _canCancelSearch: function () {
            return false;
        },

        /**
         * 编辑框失焦后,判断是否符合规则等执行事件
         * @protected
         */
        _editCompBlurValidValue: function () {
            //Sean: 校验是否符合规则
            this.checkValid();
        },

        /**
         * 编辑框获得焦点后事件,抽象方法
         * @protected
         */
        _editCompFocus: function () {
        },
        /**
         * 文本编辑框失去焦点事件,抽象方法
         * @protected
         */
        _editCompBlur: function () {
        },

        /**
         * 初始化下拉列表容器
         * @private
         */
        _initViewContainer: function () {
            if (!FR.$view_container) {
                FR.$view_container = $("<div class='view-container'/>")
                    .appendTo('body');
            }
        },

        /**
         * 下拉触发按钮样式生成
         * @private
         */
        _createStyle4TriggerBtn : function(){
            //下拉触发按钮组件样式(扁平化)
            this.arrow.appendTo(this.btn);
        },

        setEnable: function (arg) {
            FR.TriggerEditor.superclass.setEnable.apply(this, arguments);
            if (this.editComp) {
                // 如果是填报初始化控件时还没有editComp.
                if (arg === true) {
                    this.editComp.removeAttr("disabled");
                } else if (arg === false) {
                    this.editComp.attr("disabled", "disabled")
                }
            }
        },

        /**
         * 修正popup弹出的位置
         * @protected
         */
        modifyPosition: function () {
            // bug37572 快速编辑切换的时候用文本框的位置取有问题
            // bug51050 移动滚动条的话用this.options.offset就是错的
            var invalid = this.options.offset != null && this.triggerTextComp.offset().top === 0 && this.triggerTextComp.offset().left === 0;
            var eH = Math.max(parseInt(invalid ? this.options.offset.top : this.triggerTextComp.offset().top), 0);
            var eL = Math.max(parseInt(invalid ? this.options.offset.left : this.triggerTextComp.offset().left), 0);
            var wH = parseInt(this.options.height);
            var wL = parseInt(this.options.width);

            var bottomHeight = document.body.clientHeight - eH - wH;
            /*b:判断的依据应该是editcomp上下部的高度对比*/
            if (eH - $(".x-toolbar").height() < bottomHeight || eH < this.tH) {
                this.$view.css('top', eH + wH + (FR.Browser.r.gecko? 1 : 0));
                if (bottomHeight < this.tH) {
                    // 下边框高度去掉
                   // this.$view.height(bottomHeight-2);
                    //bug67918发现高度会超出的时候就立即调整高度
                    this.modifyTop(eH);
                }
            } else {
                this.modifyTop(eH);
            }
            if(eL + this.tW > document.body.clientWidth && (eL + wL > this.tW) ){
                this.$view.css('left',eL + wL - this.tW);
            }else{
                this.$view.css('left', eL);
            }
        },

        modifyTop:function( eH ){
            this.$view.css('top', (eH - this.tH > 0) ? eH - this.tH : 0);
        },
        /**
         * 下拉按钮触发事件,抽象方法,具体的控件需要实现此方法以相应按钮的点击事件
         * @abstract
         */
        onTriggerClick: function () {
        },

        /**
         * 仅支持通过class来设置图标
         * @param {String} cls 用于展示图标的css样式表类
         */
        setIcon: function (cls) {
            this.btn.attr("class", cls);
        },

        fixValue : function() {
            return 2;
        },
        fixbtnHeightValue : function() {
            return  FR.Browser.isIE8Before() && !$.support.boxModel ? 0 : 2;
            //默认给下拉按钮宽度为1px的边框
        },
        fixbtnWidthValue : function() {
            return  FR.Browser.isIE8Before() && !$.support.boxModel ? 0 : 1;
            //默认给下拉按钮宽度为1px的边框
        },
        doResize: function (give) {
            FR.TriggerEditor.superclass.doResize.apply(this, arguments);
            //尺寸兼容性计算
            var triggerTextCompWidth = give.width - this.btnWidth,
                triggerTextCompHeight = give.height,
                editCompWidth = give.width - this.btnWidth,
                editCompHeight = give.height;

            if ($.support.boxModel) {
                triggerTextCompWidth -= this.fixValue();
                triggerTextCompHeight -= this.fixValue();
                editCompWidth -= 8;
                editCompHeight -= 4;
            }else if(FR.Browser.r.ie10Compat || FR.Browser.r.ie9Compat || FR.Browser.r.ie11Compat){
                //bug:75666 ie10下兼容模式,文档选择标准,fs下拉框异常
                triggerTextCompWidth -= 3;
                triggerTextCompHeight -= this.fixValue();
            }else if(FR.Browser.isIE10()){
                //ie11下文档选择ie10,fs下的下拉按钮异常
                triggerTextCompWidth -= this.fixValue();
                triggerTextCompHeight -= this.fixValue();
            }else if(FR.Browser.isIE8()){
                if(!$.support.boxModel){
                    //bug:78023边框有空隙
                    editCompWidth -= 2;
                }else{
                    //65352 ie8下input框显示不全.
                    editCompWidth -= 3;
                }

            }
            
            //文本输入框外层容器resize
            this.triggerTextComp.css({
                width: triggerTextCompWidth,
                height: triggerTextCompHeight
            });
            //文本输入框resize
            this.editComp.css({
                width: editCompWidth,
                height: editCompHeight
            });
            if (FR.Browser.isIE()) {
                this.editComp.css("line-height", editCompHeight + "px"); // 后面-1是padding+magin
            }
            //下拉触发按钮resize
            this.btn.css({
                height: give.height - this.fixbtnHeightValue()
            });
            //下拉触发按钮中间层处理
            this.doResize4Triggerbtn(give);
            //设置水印
            if (this.options.watermark) {
                this.removeWaterMark();
                this.setWaterMark();
            }
        },

        doResize4Triggerbtn: function(give){
            var arrowHeight = this.getArrowIconHeight();
            var marginHeight=(this.btn.height() + this.fixbtnHeightValue() - arrowHeight)/2;
            this.arrow.css('margin-top',marginHeight)
        },
        /**
         * 开始编辑
         */
        startEditing: function () {
            if (this.triggerTextComp) {
                this.triggerTextComp.show();
            }
            if (this.editComp) {
                this.editComp.focus();
            }
            this.editComp.select();
            if (this.options.watermark) {
                this.removeWaterMark();
            }
        },

        /**
         * 结束编辑
         */
        stopEditing: function () {
            this.editComp.blur();
            if (this.triggerTextComp) {
                this.triggerTextComp.hide();
            }
            FR.TriggerEditor.superclass.stopEditing.apply(this, arguments);
        }
    });

    /**
     * 基础的日期时间控件
     * @class FR.BaseDateTimeEditor
     * @extends FR.TriggerEditor
     * @abstract
     */
    FR.BaseDateTimeEditor = FR.extend(FR.TriggerEditor, /**@class FR.BaseDateTimeEditor*/{
        /**
         * @private
         */
        _defaultConfig: function () {
            return $.extend(FR.BaseDateTimeEditor.superclass._defaultConfig
                .apply(), {

            });
        },
        /**
         * @private
         */
        _init: function () {
            FR.BaseDateTimeEditor.superclass._init.apply(this, arguments);
            if (this.options.value) {
                this._dealValueWithEvents(this.options.value, false);
            }
        },

        /**
         * 获取默认支持的显示格式
         * 对于手动输入的,不管设定的是什么格式的,都识别默认这几种,并转化成设定格式
         * @returns {Array} 返回格式
         */
        getDefaultSupportFormat: function () {
            return ["yyyy-MM-dd", "yyyy-MM-d", "yyyy-M-dd", "yyyy-M-d",
                "yyyy/MM/dd", "yyyy/MM/d", "yyyy/M/dd", "yyyy/M/d",
                "yyyy-MM-dd HH:mm:ss", "yyyy-M-d HH:mm:ss",
                "yyyy/MM/dd HH:mm:ss", "yyyy/M/d HH:mm:ss"];
        },

        /**
         * @param {Object} value 新值
         * @private
         */
        _dealValueWithEvents: function (value) {
            // 有的客户会用setValue(null)之类的来置空控件
            // 这个就不校验格式了
            if (FR.isEmpty(value)) {
                this.reset();
                return;
            }
            if (FR.isArray(value)) {
                value = value.toString();
            }
            var dp = value || '';
            var format = this.options.format;
            if (dp.date_milliseconds) {
                dp = new Date(dp.date_milliseconds);
            } else if (typeof value == 'string' && format) {
                //shoc: safari不支持"2013-01-01",也不支持"2013/01"和"2013-01",IE和FF不支持"2013/01"
                //IE9以下版本也不支持"2013-01-01",不支持"2013-01"
                //IE和火狐不支持'2013-01-01 01:01:01',只支持'2013/01/01 01:01:01'
                if (!this.options.customFormat) {
                    dp = FR.matchDateFormat(value, format);
                    if (dp === false) {
                        var arr = this.getDefaultSupportFormat();
                        for (var i = 0; i < arr.length; i++) {
                            var result = FR.matchDateFormat(value, arr[i]);
                            if (result) {
                                dp = result;
                                break;
                            }
                        }
                    }
                }
                else {
                    dp = FR.str2Date(value, format);
                }
            }
            // richer:ff中new Date("")是"Invalid Date",而在ie中则是"NaN"
            if (dp == "Invalid Date" || dp == "NaN" || dp === false) {
                dp = '';
            } else if (dp instanceof Date) {
                // richer:要把通用的java类型的时间转换为js时间
                dp = FR.date2Str(dp, format);
                this.options.value = dp;
            }

            this.setText(dp);
            this.options.currentDateTime = dp;
            // alex:把老的值保存在this.options.value中,用来判断isDirty
            var oldValue = this.options.value;
            this.options.value = value;
            if (arguments[1] !== false) {
                this.fireEvent(FR.Events.CHANGE, value, oldValue);
            }
        },
        /**
         * 设置起始和结束日期
         * @param {String} s  标识是起始日期还是结束日期
         * @param {String} date 日期
         */
        setStartOrEndDate: function (s, date) {
            if (!date) {
                return;
            }
            if (typeof date == 'string') {
                date = date.replace(/-/g, '/');
            }
            if (!FR.isInvalidDate(new Date(date))) {
                if (s == 'startDate') {
                    this.options.startDate = date;
                    this.std = new Date(date);
                } else if (s == 'endDate') {
                    this.options.endDate = date;
                    this.edd = new Date(date);
                }
            }
        },
        /**
         * 设置起始日期
         * @param {String} sd 起始日期
         */
        setStartDate: function (sd) {
            this.setStartOrEndDate('startDate', sd);
        },
        /**
         * 设置结束日期
         * @param {String} ed 结束日期
         */
        setEndDate: function (ed) {
            this.setStartOrEndDate('endDate', ed);
        },

        setText: function (text) {
            this.editComp.val(text);
        },

        /**
         * 还原到之前的值
         */
        recoveryValue: function () {
            this.editComp.val(this.options.oldValue);
        },

        isValidate: function (cValue) {
            var allowBlank = this.options.allowBlank !== false; // james:默认允许为空
            var format = this.options.format;
            var startDate = this.std;
            var endDate = this.edd;

            var value = cValue != null && cValue != undefined
                ? cValue
                : this.getValue();
            if (!cValue && !value && this.editComp.val()) {
                this.errorMsg = FR.i18nText("FR-Engine-Value_Not_Match");
                return false;
            }
            var regex = this.options.regex;
            // richer:优先判断填写规则
            if (regex) {
                if (typeof regex == 'string') {// String的时候,构造一个RegExp出来
                    regex = new RegExp(regex);
                }
                if (!regex.test(value)) {
                    this.errorMsg = this.options.errorMsg
                        || FR.i18nText("FR-Engine-Error_Input_Value");
                    return false;
                }
            }
            if ((!value) || ($.isArray(value) && value.length === 0)) {// 输入的值为空的时候
                if (allowBlank) {// 如果允许为空,就返回TRUE了
                    return true;
                } else {// 不允许为空,那就检测
                    this.errorMsg = this.options.errorMsg
                        || FR.i18nText("FR-Engine-Not_NULL");
                    return false;
                }
            }
            var dt = this.options.returnDate ? new Date(value) : FR.matchDateFormat(value, format);
            if (format && typeof value == 'string' && !this.options.customFormat) {
                // value可能是string(控件返回string时),也可能是Date对象,也可能是JSON对象{date_milliseconds:100000}
                // 字符串value有可能是无法构建("201307"在IE)或者构建不正确("201307"在chrome)
                if (!dt) {
                    this.errorMsg = this.options.errorMsg || FR.i18nText("FR-Engine-Error_Input_Value");
                    return false;
                }
            }
            if (startDate && new Date(dt) < new Date(startDate)) {
                this.errorMsg = this.options.errorMsg
                    || FR.i18nText("FR-Engine-Err-The_Number_Is_Less_Than_The_Minimum_Value")
                    + FR.date2Str(startDate, format);
                return false;
            }
            if (endDate && new Date(dt) > new Date(endDate)) {
                this.errorMsg = this.options.errorMsg
                    || FR.i18nText("FR-Engine-Err-The_Number_Is_Larger_Than_The_Maximum_Value")
                    + FR.date2Str(endDate, format);
                return false;
            }
            if (dt > new Date('2999/12/31') || dt < new Date('1900/01/01')) {
                this.errorMsg = "out of range";
                return false;
            }

            return true;
        },

        reset: function () {
            // reset()方法默认是用的setValue("") 这个会先进行校验,
            // 日期控件默认情况都是带有format的,赋空值校验不通过,还是改下比较合适
            this.setText("");
        }
    });

    /**
     * 这是一个抽象类。是下拉表,下拉复选框和下拉树控件的父类。
     * @class FR.BaseComboBoxEditor
     * @extends FR.TriggerEditor
     * @abstract
     * @cfg {String} name4Empty 在允许为空的时候待选列表的第一项的值
     * @cfg {Number} [searchTime=500] 手动输入指定毫秒后开始到服务器去查询符合条件的项
     * @cfg {Boolean} [directEdit=true] 允许直接编辑
     * @cfg {Boolean} [customData=true] 允许自定义值
     */
    FR.BaseComboBoxEditor = FR.extend(FR.TriggerEditor, /**@class FR.BaseComboBoxEditor*/ {

        /**
         * @private
         */
        _defaultConfig: function () {
            return $.extend(
                FR.BaseComboBoxEditor.superclass._defaultConfig.apply(), {
                    name4Empty: FR.i18nText("FR-Engine-Choose_None"),
                    // 手动输入500毫秒后开始到服务器去查询符合条件的项
                    searchTime: 500,
                    //允许直接编辑 能输入
                    directEdit: true,
                    //允许自定义值 值可以不在列表中
                    customData: true
                });
        },
        /**
         * @private
         */
        _init: function () {
            FR.BaseComboBoxEditor.superclass._init.apply(this, arguments);
        },


        initData: function () {
            FR.BaseComboBoxEditor.superclass.initData.apply(this, arguments);
            if (this.options.controlAttr) {
                this.setSource(this.options.controlAttr)
                delete this.options.controlAttr
            }
        },

        /**
         * 设置数据联动源
         * @param source {JSON} 数据联动源
         */
        setSource: function (source) {
            if (source["data"]) {
                var para = {
                    parameter: {
                        dependence: this.getDependenceObj(),
                        startIndex: 0,
                        limitIndex: this.options.limitData
                    }
                }
                this.options.data.setData(para, source["data"]);
            }
            if (source["value"]) {
                if (this.editComp) {
                    this.setValue(source["value"], false);
                }
            }
            this.shouldReBuildList();
        },

        /**
         * @private
         * @param start 起始数据索引
         * @param limit 结束数据索引
         * @returns {Object} 参数
         */
        allPara: function (start, limit) {
            var para = this.createDependencePara4Data();
            if (this.searchText || this.searchText === 0 || this.searchText == '0') {
                para.parameter.dataFilter = this.searchText;
            }

            para.parameter.startIndex = start ? start : 0;
            para.parameter.limitIndex = limit ? limit : this.options.limitData;
            return para;
        },

        /**
         * 获取下拉列表
         * @private
         */
        _getViewList: function () {

        },

        getText: function () {
            return this.editComp.val();
        },
        /**
         * 获取下拉列表内的元素数
         * @returns {*}
         */
        getItemsLength: function () {
            return this.options.data.getLength();
        },

        /**
         * @private
         */
        _onEnterPressed: function () {
            this._selectWithoutTriggerEvent();
            this.fireEvent(FR.Events.AFTEREDIT, this.selectedIndex < this.getItemsLength() ? this._getSelectedItem().text() : '');
        },

        /**
         * 不触发下拉按钮事件而选中一个元素
         * @private
         */
        _selectWithoutTriggerEvent: function () {
            if ((this.getItemsLength() > 0)
                && (this.selectedIndex < this.getItemsLength())) {
                this.setText(this._getSelectedItem().text())
                this.inList = true;
            } else {
                this.clearText();
                this.searchText = "";
                this.options.need2BuildList = true;
            }
            this.checkValid();
            this.collapse();
        },

        /**
         * 从下拉列表中查找数据
         * @param value {String} 要查找的数据
         * @returns {Boolean} 返回是否该数据存在于下拉列表中
         * @private
         */
        _findInList: function (value) {
            var records = this.options.data.getRecords();
            for (var i = 0, len = records.length; i < len; i++) {
                // shoc:数字和字符串不区分,改成双等,bug30316,真实值显示值都算
                // 不选的时候value为"",注意""==0为true
                if ((value != "" && (records[i].getValue() == value || records[i].getShowValue() == value))
                    || (value == "" && (records[i].getValue() === value || records[i].getShowValue() === value))) {
                    this.inList = true;
                    if(this.$view){
                        this._setSelectedIndex(i);
                    }
                    return records[i].getShowValue();
                }
            }
            if(this.options.data.options.dataSource) {
                var dataSource = this.options.data.options.dataSource;
                if (dataSource._findShowValue) {
                    var showValue = dataSource._findShowValue(value);
                    if (showValue) {
                        this.inList = true;
                        return showValue;
                    }
                    return false;
                }
            }

            this.inList = false;
            return false;
        },

        setText: function (text) {
            this.editComp.val(text);
        },

        /**
         * 清空文本编辑框
         */
        clearText: function () {
            this.editComp.val("");
        },

        /**
         * 获取选中的元素
         * @returns {*} 返回选中的内容
         * @private
         */
        _getSelectedItem: function () {
            return this.selectedItem;
        },

        /**
         * 获取选中的元素的位置
         * @returns {Number} 返回位置编号,如果没有选中元素则返回-1
         * @private
         */
        _getSelectedIndex: function () {
            return this.selectedIndex != null ? this.selectedIndex : -1;
        },

        /**
         * 获取选中的元素
         * @returns {Number} 返回位置编号,如果没有选中元素则返回-1
         */
        getSelectedIndex: function () {
            return this._getSelectedIndex();
        },

        /**
         * 滚动选中指定位置的下拉列表子项元素
         * @param {Number} idx 位置索引
         * @private
         */
        _setSelectedIndex: function (idx) {
            if (this.selectedItem) {
                this.selectedItem.removeClass('fr-combo-selected');
            }
            this.selectedItem = this.$view.children('.fr-combo-list-item:eq(' + idx + ")");
            this.selectedIndex = idx;
            if (idx >= 0) {
                this.selectedItem.addClass('fr-combo-selected').__scroll2View__(this.$view, false);
            }
        },

        /**
         * 设置当前被选中的一项
         * @param index 位置索引
         */
        setSelectedIndex: function (index) {
            this._setSelectedIndex(index);
            this._onEnterPressed();
        },

        /**
         * 还原到之前的值
         */
        recoveryValue: function () {
            this.editComp.val(this.options.oldValue);
            this.searchText = this.options.oldValue;
            this.shouldReBuildList();
        },

        /**
         * 需要重新生成下拉列表
         */
        shouldReBuildList: function () {
            this.options.need2BuildList = true;
        },

        /**
         * 返回加入允许为空一项的下拉列表的总元素个数
         * @returns {number} 返回个数
         */
        considerAllowBlankLength: function () {
            return this.getItemsLength()
                + (this.options.allowBlank === false ? 0 : 1);
        },

        /**
         * 校验是否符合规则
         * @returns {Boolean} 返回是否符合规则
         */
        isValidate: function (cValue) {
            if (!FR.BaseComboBoxEditor.superclass.isValidate.apply(this, arguments)) {
                return false;
            }
            var value = cValue != null ? cValue : this.getValue();
            if (!this.options.customData && !FR.isEmpty(value) && !this.isValueInList(value)) {
                this.errorMsg = FR.i18nText("FR-Engine-Not_In_List");
                return false;
            }

            return true;
        },

        isValueInList: function(value) {
            return false;
        },

        /**
         * 不管是每次取值都从后台读取匹配结果还是从已经加载的数据中匹配,都不是很好
         * todo 弄成this.value存放控件结果值
         * @return {*}
         */
        getValue: function () {
            var dp = this.getText();
            var val = null;
            var records = this.options.data.getLoadedRecords();
            var index = this._getSelectedIndex();
			if (index > -1 && index < records.length){
			   val = this._getValue(records[index],dp,index);
                if(val != null){
                    return val;
                }
            }
            var dataSource = this.options.data.options.dataSource;
            if (records.length === 0) {
                if (dataSource._findShowValue) {
                    var res = dataSource._findShowValue(dp, false);
                    if (res != null) {
                        val = res;
                        return val;
                    }
                }
            } else {
                for (var i = 0, len = records.length; i < len; i++) {
                    val = this._getValue(records[i],dp,i);
                    if(val != null){
                        return val;
                    }
                }
            }
            // 到这还没return说明值没在列表中允许 允许自定义值的话就返回显示值了
            //从某一版本开始数据并没有一次加载,而是带有limitindex了。这边如果数据量超过limitindex就会有问题
            if (val == null && dataSource._findShowValue) {
                val = dataSource._findShowValue(dp, false);
            }
            if(val != null){
                return val;
            }
            if (this.options.customData) {
                return dp;
            }else if(!FR.isEmpty(dp)){
                return "invalidatevalue";
            }
        },

        /**
         * 根据显示值获取实际值
         * @param records 实际值
         * @param text 显示值
         * @param index 序号
         * @returns {*} 实际值
         * @private
         */
        _getValue: function(records,text,index){
            var record = records.getShowValue();
            var val;
            if(typeof record == 'string'){
                record = $.trim(record);
            }
            //下拉框选择'不选', 返回的"" == 0
            //text 是从框里getText()出来的字符串, record也转为字符串吧
            if(record === text || record + '' === text || records.getShowValue() === text){
                val = records.getValue();
                if (this.$view) {
                    this._setSelectedIndex(index);
                }
            }
            return val;
    },

        setValue: function (value) {
            //wei : setValue的时候不提示是否输错,在stopCellEditing的时候再提示。
            if (!this.isValidate(value)) {
                return false;
            }
            if ((value || value === 0) && this.options.watermark) {
                this.clearWaterMark();
            }
            if (arguments[1] != undefined) {
                this._dealValueWithEvents(value, arguments[1]);
            } else {
                this._dealValueWithEvents(value);
            }
        },

        _dealValueWithEvents: function (value) {
            var oldValue = this.getValue();
            this.options.oldValue = oldValue;
            // 0 == ""
            if (value === "") {
                this.editComp.val("");
                return;
            }
            var dp = value;
            var find = this._findInList(value);
            if (find !== false) {
                dp = find;
            }
            // 如果是today等计算出的时间传过来,无格式的话Thu Apr 18 00:00:00 CST 2013转化成yyyy-MM-dd
            if (dp && dp.length > 24 && !FR.isInvalidDate(new Date(dp)) && this.options.type != "datetime") {
                dp = FR.date2Str(new Date(dp), "yyyy-MM-dd");
            }
            this.setText(dp);
            if (arguments[1] !== false) {
                this.fireEvent(FR.Events.CHANGE, value, oldValue);
                // 下拉框没有change,用触发afteredit的方法解决关联控件赋值问题,
                // 但是如果是编辑后事件调用的话就死循环了,这时候加false参数不触发这句
                this.fireEvent(FR.Events.AFTEREDIT);
            }
        },

        reset: function () {
            // 重置,目前主要用于联动时,与当前控件相关的控件值改变时,需要做重置操作
            FR.BaseComboBoxEditor.superclass.reset.apply(this, arguments);
            this.shouldReBuildList();
            delete this.searchText;
            delete this.emptyContent;
            // b:加属性让用户选择联动时是否自动加载并选择第一个值,请加界面设置,默认不选
            if (this.options.linkAutoChoose) {
                this.onTriggerClick();
                this._setSelectedIndex(0);
                this._selectWithoutTriggerEvent();
            }
        }
    });
})(jQuery);