/*
* 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);