/* * Copyright (c) 2001-2014,FineReport Inc, All Rights Reserved. */ ; (function ($) { /** * 下拉框控件 * * @example * var $el = $('<div>').css({position : 'absolute', top : 5, left : 40}).appendTo('body'); * var editor = new FR.ComboBoxEditor({ * renderEl : $el, * directEdit : true, //是否允许直接编辑 * allowBlank : false, //是否允许为空 * widgetUrl : null, //支持模糊搜索,异步取数请求url * fontSize : 14, //显示的字体大小 * width : 120, * height : 24, * maxCount : 3, //一页显示的记录数 * sonHeight : 24, //子项元素高度 * items : [ //本地取数方式,优先于widgetUrl * {text : "一一", value : "aa"}, * {text : "二二", value : "bb"}, * {text : "三三", value : "cc"}, * {text : "四四", value : "dd"} * ] * }); * * @class FR.ComboBoxEditor * @extends FR.BaseComboBoxEditor * * @cfg {JSON} options 属性配置 * @cfg {Number} [options.maxCount=10] 一页显示的记录个数 * @cfg {Number} [options.sonHeight=18] 下拉框单项高度 * @cfg {Object} [options.value=''] 默认值 * @cfg {Number} [options.limitData=500] 单次加载的数据量 * @cfg {Boolean} [options.autoFixWidth=true] 自动调整列表宽度 * @cfg {Boolean} [options.allowBlank=true] 允许为空 * @cfg {Number} options.fontSize 字体大小 * @cfg {String} options.widgetUrl 下拉列表数据 * @cfg {Number} options.width 控件宽度 * @cfg {Number} options.height 控件高度 * @cfg {Array} options.items 下拉列表数据,这一项优先于widgetUrl */ FR.ComboBoxEditor = FR.extend(FR.BaseComboBoxEditor, /**@class FR.ComboBoxEditor*/{ /** * @private */ _defaultConfig: function () { return $.extend(FR.ComboBoxEditor.superclass._defaultConfig.apply(), { name4Empty: FR.i18nText("FR-Basic_Choose_None"), maxCount: 10, sonHeight: 18, value: '', limitData: 500, autoFixWidth: true }); }, /** * @private */ _init: function () { FR.ComboBoxEditor.superclass._init.apply(this, arguments); this._dealSearch(); var o = this.options; //滚动条宽度 this.scrollBarWidth = 20; /*每个Combo对应在一个div -> $view*/ if (!this.$view) { this.$view = $('<div/>').height(20).appendTo(FR.$view_container); } this.$view.hide(); this.shouldReBuildList(); if (this.options.data && this.options.data.isLocalSource()) { if (this.options.dependence) { this.options.data.resetStatus(this.allPara.apply(this, arguments)); } var data = this.options.data.getRecords(); this._setItems(data); this.checkViewScroll(data); this.options.need2BuildList = false; this.options.need2FixWidth = true; } FR.applyStyles(this.editComp, o.style); }, /** * 绑定模糊搜索功能 * @private */ _dealSearch: function () { var self = this, o = this.options; if (this.options.widgetUrl) { this.options.searchData = new FR.AjaxSearchData({ url: this.options.widgetUrl }); this.editComp.keyup(function (event) { // 不允许直接编辑 if (!self.options.directEdit) { return; } /* 如果在0.5秒内焦点离开了 文本框没有了 这时候取editComp的offset进行位置校正就不对了*/ /* 如果在0.5秒内焦点离开并且不能自定义值 不太好处理 设置状态位 self.searchCancel*/ if (self.options.offset == undefined) { self.options.offset = {'left': self.editComp.offset().left, 'top': self.editComp.offset().top}; } /* richer:需要可直接编辑的时候才提供快速定位*/ if (!FR.isNavKeyPress(event)) { setTimeout(function () { if (self.searchText == self.editComp.val() && event.keyCode != FR.keyCode.BACKSPACE) { if (!self.isExpanded()) { self.expand(); } return; } /* 下拉复选框改用真实值来getValue的话 需要判断是不是手输的值*/ self.edited = true; if (self.searchCancel !== true) { self.searchText = self.editComp.val(); self._doBeforeSearch(); /* ajaxSearch中加载数据可能要好久 如果在中间切到其他控件了就可能出问题*/ /* editComp.blur中用inList==fasle 如果是undefined不操作 等待数据加载完再校验输入值是否在list中*/ self.inList = false; self._ajaxSearch(); self.fireEvent(FR.Events.AFTEREDIT); self.searchCancel = false; } else { self.searchCancel = undefined; } }, o.searchTime); } }); } }, /** * 模糊搜索,生成的下拉列表 * @private */ _ajaxSearch: function () { this.embellishView(); this.$view.empty(); this.$view.height(30); this.$view.__loadingMoreData__(true); this.modifyPosition(); this.$view.show(); var para = this.allPara.apply(this, arguments); this.options.searchData.resetStatus(para); var self = this; var searchTimes = self.lastAjaxSearchTimes ? (self.lastAjaxSearchTimes + 1) : 1; self.lastAjaxSearchTimes = searchTimes; this.options.searchData.loadObject(function (data) { if (searchTimes < self.lastAjaxSearchTimes) { return; } self.options.data.setData(para, data); self.checkViewScroll(self.options.data.getData()); self._setItems(self.options.data.getData()); self.$view.__loadingMoreData__(false); self.$view.hide(); self.options.need2BuildList = false; self._createVieList(); self.__makeSureInputValueInResList(); if (self.options.data.getData().length > 0) { self.setFocusWithIndex(0); } }); }, /** * @returns {boolean} * @private */ _canCancelSearch: function () { return true; }, __makeSureInputValueInResList: function () { var self = this; var viewList = self._getViewList(); if (viewList.length !== 0) { if (self.searchText == "") { self.inList = undefined; } else { for (var i = 0; i < viewList.length; i++) { if (viewList.eq(i).text() == self.searchText) { self.inList = true; break; } self.inList = false; } } } else { //wei : 说明这时候输入的内容不是下拉列表中的内容。 self.inList = false; } if (self.inList === false && !self.options.customData) { this.errorMsg = FR.i18nText("FR-Basic_Not_In_List"); this.invalidateCss(); } else { this.validateCss(); } }, isValueInList: function (value) { return this._checkValueInResList(value); }, /** * 检验输入值是否存在于下拉列表中 * @private */ _checkValueInResList: function (value) { var txt = value || this.editComp.val(); var dataSource = this.options.data.options.dataSource; if (dataSource._findShowValue) { var res = dataSource._findShowValue(txt, false); this.inList = res != null; } else { var viewList = this._getViewList(); this.inList = false; if (viewList.length !== 0) { for (var i = 0; i < viewList.length; i++) { if (viewList.eq(i).text() == txt) { this.inList = true; break; } } } } /*Sean: true和undefined都表示存在,而false表示不存在于列表中*/ if (this.inList === false) { this.errorMsg = FR.i18nText("FR-Basic_Not_In_List"); return false; } else { return true; } }, /** * 按键后,模糊搜索前事件,抽象方法 * @private */ _doBeforeSearch: function () { }, /** * 重新构建下拉列表 * @param items 列表选项 */ rebuild: function (items) { this.options.data = null; this.options.widgetUrl = null; this.element.empty(); this.$view.empty(); this.options.items = items; this.options.need2BuildList = true; if (items.widgetUrl) { this.options.widgetUrl = items.widgetUrl; } this._init(); }, /** * 获取下拉列表的所有子项 * @returns {jQuery} 返回所有子项dom * @private */ _getViewList: function () { return this.$view.children('.fr-combo-list-item'); }, /** * 选中下拉列表中指定位置的一项 * @param {Number} index 位置索引 */ setFocusWithIndex: function (index) { $(".fr-combo-list-item", this.$view).removeClass("fr-combo-selected"); this.focusIndex = index; $(".fr-combo-list-item", this.$view).eq(index).addClass("fr-combo-selected"); }, /** * 取数方法的实现 * @returns {*} */ getData: function () { var dp = this.getText(); var val = dp, records = this.options.data.getLoadedRecords(), index = this._getSelectedIndex(); if (index > -1 && index < records.length) { var record = records[index].getShowValue(); if (typeof record == 'string') { record = $.trim(record); } if (record == dp) { return records[index].getContent(); } } else { for (var i = 0, len = records.length; i < len; i++) { if (records[i].getShowValue() == dp) { val = records[i].getContent(); if (this.$view) { this._setSelectedIndex(i); } break; } } return val; } }, /** * @param {Event} e 鼠标事件 * @private */ _onKeyDown: function (e) { var self = e.data; switch (e.keyCode) { case FR.keyCode.DOWN : { if (!self.isExpanded()) { self.onTriggerClick(); } else { if (self.focusIndex == undefined) { self.focusIndex = self._getSelectedIndex() || 0; } if (self.focusIndex < (self.considerAllowBlankLength() - 1)) { self._setItemFocus(self.focusIndex + 1, self.focusIndex); self.focusIndex = self.focusIndex + 1; } else { self._setItemFocus(0, self.focusIndex); self.focusIndex = 0; } } e.stopEvent(); break; } case FR.keyCode.UP : { if (self.isExpanded()) { if (self.focusIndex == undefined) { self.focusIndex = self._getSelectedIndex(); } if (self.focusIndex - 1 >= 0) { self._setItemFocus(self.focusIndex - 1, self.focusIndex); self.focusIndex = self.focusIndex - 1; } else { self._setItemFocus(self.considerAllowBlankLength() - 1, self.focusIndex); self.focusIndex = self.considerAllowBlankLength() - 1; } e.stopEvent(); } break; } case FR.keyCode.ENTER: { self.collapse(); break; } case FR.keyCode.TAB : { if (self.isExpanded()) { if (self.focusIndex != undefined) { self._setSelectedIndex(self.focusIndex); } else { self.collapse(); self.editComp.blur(); e.stopEvent(); break; } self._onEnterPressed(); if (self.editComp.val() == '' && self.options.allowBlank !== false) { self.inList = true; } e.stopEvent(); } break; } } }, /** * 点击下拉框右侧小按钮事触发的函数 */ onTriggerClick: function () { /* 705改成点击下拉列表的选项才出发点击事*/ if (!this.isEnabled()) { return; } if (this.isExpanded()) { this.collapse(); } else { this._createVieList(); } }, /** * 生成下拉列表,并加载数据 * @param needExpand 是否需要展开下拉列表 * @private */ _createVieList: function (needExpand) { this.embellishView(); /*wei:记录下一开始选中的项*/ if (this.options.need2BuildList) { this.$view.empty(); if (needExpand !== false) { this.$view.height(30); /*重设高度,用于显示loading图标啊*/ this.tH = 30; this.tW = this.$view.width(); this.modifyPosition(); this.$view.show(); } this.$view.__loadingMoreData__(true); if (this.options.data) { this.options.data.resetStatus(this.allPara.apply(this, arguments)); var data = this.options.data.getData(); this.checkViewScroll(data); this._setItems(data); } this.$view.hide(); this.$view.__loadingMoreData__(false); this.options.need2BuildList = false; this.options.need2FixWidth = true; } if (this.options.need2FixWidth !== false) { this.fixViewWidth(); this.options.need2FixWidth = false; } if (needExpand !== false) { this.expand(); this.modifyPosition(); } }, /** * 滚动加载下拉列表数据 * @private */ scrollLoadMoreData: function () { if (this.isLoadingData) { return; } this.isLoadingData = true; this.$view.__loadingMoreData__(true); this.options.data.resetStatusKeepData(this.allPara(this.options.data.getLength())); var data = this.data2Add(); this.checkViewScroll(data); this.addData2View(data); this.isLoadingData = false; }, /** * 添加值 * @returns {*} */ data2Add: function () { return this.options.data.appendData(); }, /** * 将数据生成为子项元素,添加到下拉列表中 * @param {Array} data 数据 */ addData2View: function (data) { var txt = this.editComp.val(); var defaultIdx = -1; if (this.$view) { if (!this.emptyContent) { var emptyContent = this._checkAndAddEmptyContent(); } else { this.initContent(this.emptyContent, this.options.name4Empty, -1); } var frag = document.createDocumentFragment(); var len = this.options.data.getLength(); for (var i = len - data.length; i < len; i++) { var ri = i + data.length - len; var sondi = $('<div/>'); frag.appendChild(sondi[0]); var showValue = data[ri].getShowValue(); this.initContent(sondi, showValue, i); if (defaultIdx < 0 && showValue == txt) { defaultIdx = ri; } } //这个宽度要自动调整, 不然控件联动下拉框时, 上一次联动选项的宽度会影响到下一个 $(this.$view[0]).css('width', 'auto'); this.$view[0].appendChild(frag); this.$view.append(emptyContent || this.emptyContent); this.$view.__loadingMoreData__(false); this._setSelectedIndex(defaultIdx); //因为上面是auto的, 如果小于下拉框宽度就不好看了. if (this.$view.width() < this.element.width()) { var ew = this.element.width(); //zack:这边如果有滚动条的话要加上滚动条的宽度20 if (this.addedScrollWidth) { ew += this.scrollBarWidth; } this.$view.width(ew - 2); } } }, /** * 初始化一个子项元素 * @param {jQuery} $dom DOM对象 * @param {String} showValue 显示值 * @param {Number} index 位置索引 */ initContent: function ($dom, showValue, index) { if (showValue == null) { showValue = ''; } var self = this; $dom.height(this.options.sonHeight).attr("title", showValue).text(showValue) .addClass(index > -1 ? 'fr-combo-list-item' : 'fr-combo-list-item fr-combo-list-item-noselect') .hover(function (e) { self.setFocusWithIndex(index); setTimeout(function (e) { if (!e) { return; } var target = $(e.target); if (self.$view[0].style.display != "none" && target.isChildAndSelfOf($(this).parent().children())) { $(this).removeClass("fr-combo-selected"); } }, 10); }) .click(function (e) { self.inList = true; self.fireEvent(FR.Events.CLICK); self._setSelectedIndex(index > -1 ? index : self.getItemsLength()); self._onEnterPressed(); }); }, /** * 如果允许为空,则生成'不选'一项选择项 * @returns {jQuery} 返回生成的dom对象 * @private */ _checkAndAddEmptyContent: function () { if (this.options.allowBlank === false) { return; } this.emptyContent = $('<div/>'); this.initContent(this.emptyContent, this.options.name4Empty, -1); return this.emptyContent; }, /** * 判断是否需要滚动加载 * @param {Array} data 一次加载的数据限制个数 */ checkViewScroll: function (data) { this.$view.need2Scroll = this.options.limitData <= data.length; }, /** * 渲染绘制下拉列表 * @private */ embellishView: function () { if (this.viewEmbellished) { return; } $(".fr-combo-list").hide(); var self = this; if (!this.$view) { this.$view = $('<div/>').appendTo(FR.$view_container).height(20); } this.$view.addClass('fr-combo-list') .css({ position: 'absolute', width: 'auto', 'z-index': '999' }) .scroll(function () { /*wei : ==的时候ie不会执行,改成>=*/ if (self.$view.need2Scroll && $(this).scrollTop() + $(this).height() >= this.scrollHeight) { self.scrollLoadMoreData(); } }); this.viewEmbellished = true; }, /** * 设置下拉框的内容 * @private */ _setItems: function (records) { var sH = this.options.sonHeight, rl = this.considerAllowBlankLength(); var count = this.options.maxCount || 10; this.tH = rl > count ? (sH + 2) * count : (sH + 2) * rl; this.$view.height(this.tH); this.addData2View(records); this.tW = this.$view.width(); }, /** * 展开下拉列表 */ expand: function () { if (this.isExpanded()) { return; } this._showView(); $(document).bind('mousedown', this, this.collapseIf).bind('mousewheel', this, this.collapseIf); if (this.options.write && this.options.write.lgp) { this.options.write.lgp.$container.bind('scroll', this, this.collapseIf); } if (document.activeElement != this.editComp[0]) { this.editComp.focus(); } this.fireEvent(FR.Events.EXPAND); }, /** * 显示下拉列表 * @private */ _showView: function () { this.$view.show(); }, /** * 滚动切换选中的子项元素(仅仅样式改变) * @param {Number} idx 新位置索引 * @param {Number} lastidx 旧位置索引 * @private */ _setItemFocus: function (idx, lastidx) { var viewList = this.$view.children('.fr-combo-list-item'); $(viewList[lastidx]).removeClass('fr-combo-selected'); $(viewList[idx]).addClass('fr-combo-selected').__scroll2View__(this.$view, false); }, setEnable: function (arg) { FR.ComboBoxEditor.superclass.setEnable.apply(this, arguments); if (arg === false) { this.collapse(); } }, setVisible: function (arg) { FR.ComboBoxEditor.superclass.setVisible.apply(this, arguments); if (arg === false) { this.collapse(); } }, /** * 判断是否正在过滤字段 * @returns {Boolean} 返回是否正在过滤 */ isFiltering: function () { return !FR.isEmpty(this.searchText); }, /** * 调整下拉列表宽度(处理兼容问题) * @private */ fixViewWidth: function () { /* TODO Sean: 代码质量问题,兼容最好重做*/ /* shoc:IE6和IE7中框子的宽度有问题,调整下,自适应有问题,按字符计算了*/ if ($.browser.msie && $.browser.version < '8.0') { var width2 = 0; var listItems = $(".fr-combo-list-item", this.$view); for (var i = 0; i < listItems.length; i++) { var len = FR.byteLength(listItems.eq(i).text()) * 6 + 30; width2 = Math.max(width2, len); } this.$view.width(this.options.mutiSelection ? width2 + 30 : width2 + 10); } if (!$.browser.msie && this.$view.children().length > this.options.maxCount && !this.addedScrollWidth) { this.$view.width(this.$view.width() + this.scrollBarWidth); this.addedScrollWidth = true; } if (this.$view.width() < this.element.width()) { var ew = this.element.width(); //jim:表单下,下拉列表宽度比控件宽度大2,导致下拉框控件在边界时会时body出现滚动条 this.$view.width(this.element.width() - 2); } if ($.browser.msie && $.browser.version < '8.0' && this.$view.width() < 120) { this.$view.width(120); } if ($.browser.msie) { this.$view.css('overflow-x', 'visible'); } } }); $.shortcut("combo", FR.ComboBoxEditor); })(jQuery);