/** * Tag显示的下拉复选框控件 * @class FR.TagCheckBoxEditor * @extends FR.CheckBoxEditor */ FR.TagCheckBoxEditor = FR.extend(FR.CheckBoxEditor, /**@class FR.TagCheckBoxEditor*/{ _defaultConfig: function () { return $.extend(FR.TagCheckBoxEditor.superclass._defaultConfig.apply(), { //标签样式的基础类 tagBaseClass: 'fr-tageditor', //文本编辑框的最小宽度 minWidth4Edit: 24, //标签间距 tagMargin: 4, //动画速度 animateSpeed: 100 }); }, _init: function () { FR.TagCheckBoxEditor.superclass._init.apply(this, arguments); this._initTagContainer(); this.startTagIdx = -1; //Sean: 用于标识所生成的第一个tag在this.value中的索引位置 this.widthFix = 0; if(FR.Browser.isIE6Before()){ this.widthFix = 4; } }, _editCompBlur: function () { if (this.options.watermark && this.text && this.text.length > 0) { //Sean: 带tag的控件需要延后处理水印,因为input在失焦后肯定是没有值的,会产生水印。 this.removeWaterMark.defer(0, this); } }, /** * 编辑框失焦后,判断是否符合规则等执行事件 * @private */ _editCompBlurValidValue: function () { //只需要校验是否为空即可 if (this.options.allowBlank === false && (!this.text || this.text.length === 0)) { this.errorMsg = this.options.errorMsg || FR.i18nText("FR-Base_NOT_NULL_Des"); this.invalidateCss(); } else { this.validateCss(); } //为啥要重新构建? 重新构建会导致69633, 第二次下拉的时候数据用了错误的缓存. // this.options.need2BuildList = true; this.searchText = ""; var val = this.editComp.val(); if(val != ""){ val = this._getEditTagFullValue(val); this._appendTagFromInput(val); this.editComp.val(""); this._editCompBlur(); } }, _doBeforeSearch: function () { //Sean: Override. Do Nothing. }, /** * 初始化Tag层 * @private */ _initTagContainer: function () { var opts = this.options; opts.minWidth4Edit = Math.max(2*opts.fontSize, opts.minWidth4Edit); //所有tag的容器层 var height = this.editComp.height(), tagClz = opts.tagBaseClass; //所有tag的容器外层(限制显示宽度) this.tagContainer = $('<div/>').addClass(tagClz + '-container').height(height) .prependTo(this.triggerTextComp); //所有tag的容器内层(自适应内容宽度,用于左右平移显示) this.tagWrap = $('<span/>').addClass(tagClz + '-wrapper').appendTo(this.tagContainer); }, /** * 绑定tag事件 * @param {jQuery} tag tag对象 * @private */ _bindEvent2Tag: function (tag) { var self = this, o = this.options; //点击事件 tag.click(function () { self._setTagSelect($(this)); }); //双击事件 tag.dblclick(function () { if(o.directEdit !== false && o.customData !== false){ self._editTag($(this)); } }); }, /** * 对Tag进行编辑 * @param {jQuery} tagObj 需要编辑的Tag对象 * @private */ _editTag: function (tagObj) { var index = this.tagWrap.children().index(tagObj) + this.startTagIdx + 1; tagObj.hide(); var tagEditComp = $("<input type='text'/>").addClass('fr-tageditor-tag-edit') .val(tagObj.text()) .css({ width: tagObj.outerWidth(), 'font-size': this.options.fontSize }) .insertAfter(tagObj); this.isTagEditing = true; var self = this; tagEditComp.blur(function () { self.collapse(); self.isTagEditing = false; var value = $(this).val(); $(this).remove(); if (value === "") { self._removeTag(tagObj); }else{ tagObj.text(value); value = self._getEditTagFullValue(value); self._spliceTagData(index, value); tagObj.show(); self._loadMoreTags(self.text); self._modifyTagPosition(); self._moveViewToShow(tagObj); } self.fireEvent(FR.Events.STOPEDIT); } ); tagEditComp.keyup(function(e) { var key = e.keyCode; if (!FR.isNavKeyPress(e)) { self._spliceTagData(index, tagEditComp.val()); self.fireEvent(FR.Events.AFTEREDIT); }else if(key === FR.keyCode.ENTER){ $(this).blur(); } }); tagEditComp.focus(); }, /** * @param {Array} text 文本内容集合 * @private */ _setCompText: function (text) { if(this.tagWrap){ this.tagWrap.empty(); this.startTagIdx = text.length - 1; this._loadMoreTags(text); this._modifyTagPosition(); this._moveViewToShow(); }else{ FR.TagCheckBoxEditor.superclass._setCompText.apply(this, arguments); } }, /** * 分步加载Tag * @param {Array} text 文本内容集合 * @protected */ _loadMoreTags: function(text){ if(this.startTagIdx >= 0){ var minWidth4Tags = this.element.width() - this.options.minWidth4Edit - this.btnWidth; while (this.tagWrap.width() < minWidth4Tags && this.startTagIdx >= 0) { this._createTagFromText(text[this.startTagIdx]).prependTo(this.tagWrap); this.startTagIdx--; } } }, /** * 从文本内容生成一个Tag * @param {String} text 文本内容 * @protected */ _appendTagFromInput: function (text) { if (this.checkValid(text)) { if ($.inArray(text, this.text) === -1) { this._pushTagData(text); this._createTagFromText(text).appendTo(this.tagWrap); this._modifyTagPosition(); this._moveViewToShow(); var checkArr = $.grep(this.ck_el_array, function (ck_el) { return ck_el.getText() == text; }) if (checkArr && checkArr[0]) { checkArr[0].changeBoxState(true); } this.fireEvent(FR.Events.AFTEREDIT); } } else { FR.Msg.toast(this.errorMsg); } }, _getEditTagFullValue: function(newText) { return newText; }, _pushTagData: function(text) { if (!this.text) { this.text = []; } this.text.push(text); }, _spliceTagData: function(idx, newText) { if (newText == undefined) { this.text.splice(idx, 1); } else { this.text.splice(idx, 1, newText); } }, /** * 移除一个Tag * @param {jQuery} tagObj tag对象 * @param {Boolean} isLast 是否排在最后的Tag * @private */ _removeTag: function (tagObj, isLast) { if (isLast) { this.text.pop(); } else { var index = this.tagWrap.children().index(tagObj) + this.startTagIdx + 1; this._spliceTagData(index); } var $next = tagObj.next(); tagObj.remove(); this.fireEvent(FR.Events.AFTEREDIT); this.inAllSelectModel = false; this.options.need2BuildList = true; this._loadMoreTags(this.text); this._modifyTagPosition(); this._setTagSelect($next); }, _getCompText: function () { this.text = this.text || []; return this.text.slice(0);//Sean:不传递指针,所以使用slice(0)最快地clone一个数组 }, /** * 将输入的文本信息生成Tag * @param {String} text 文本内容 * @returns {*|jQuery} 返回生成的Tag对象 * @private */ _createTagFromText: function (text) { var opts = this.options; var t = text; if ($.isArray(text)) { t = text[text.length - 1]; } //不生成空文本的tag if (FR.isEmpty(t)) { return $(''); } var height = this.editComp.height(); var tagClz = this.options.tagBaseClass; //tag层 var tagSpan = $("<span/>").addClass(tagClz + '-tag') .text(t) .css({ 'line-height': height + 'px', 'margin': '0 ' + opts.tagMargin / 2 + 'px', 'font-size': this.options.fontSize }); //绑定事件 this._bindEvent2Tag(tagSpan); return tagSpan; }, /** * 调整结果标签以及文本框的位置和宽度 * @protected */ _modifyTagPosition: function () { var opts = this.options; var minWidth = opts.minWidth4Edit; var tagClz = opts.tagBaseClass; var $container = $('.' + tagClz + '-container', this.triggerTextComp); var editWidth = $.support.boxModel ? this.triggerTextComp.width() : this.triggerTextComp.width() - 2; var tagsWidth = this.tagWrap.width(); if (editWidth - tagsWidth < minWidth) { this.editComp.outerWidth(minWidth - this.widthFix); $container.width(editWidth - minWidth); } else { this.editComp.outerWidth(editWidth - tagsWidth - this.widthFix); $container.width(tagsWidth); } }, /** * 选中指定的Tag * @param {jQuery} tagObj tag对象 * @private */ _setTagSelect: function (tagObj) { var tagClz = this.options.tagBaseClass; var selectedId = tagClz + '-tag-select'; $('#' + selectedId, this.tagWrap).removeAttr('id'); if (tagObj) { //tag上绑定键盘操作,包括左右方向键选择和DELETE,BACKSPACE var self = this; var tagOpts = function (e) { if(self.isTagEditing){ return; } if (e.keyCode == FR.keyCode.DELETE || e.keyCode == FR.keyCode.BACKSPACE) { FR.Keys.unreg(tagOpts); self._removeTag(tagObj); } else if (e.keyCode == FR.keyCode.LEFT) { if (tagObj.prev().length > 0) { self._setTagSelect(tagObj.prev()); } } else if (e.keyCode == FR.keyCode.RIGHT) { self._setTagSelect(tagObj.next()); if (tagObj.next().length === 0) { self.editComp.focus(); } } }; FR.Keys.reg(tagOpts); $('body').bind('mousedown.tagselect', function(e) { if (!$(e.target).isChildAndSelfOf(self.tagWrap)) { FR.Keys.unreg(tagOpts); $('#' + selectedId, self.tagWrap).removeAttr('id'); } }); tagObj.attr('id', tagClz + '-tag-select'); this._moveViewToShow(tagObj); } else { this._moveViewToShow(); } }, _editCompFocus: function () { var val = this.editComp.val(); if(val != ""){ this._setCompText(this.text); if(!this.isFiltering()){ this.editComp.val(""); } }else{ this._setTagSelect(); } }, /** * 将所有Tag平移使指定对象出现在可视范围 * @param {Number|jQuery} tagObj 需要显示的元素;若为空,则表示移动到最后一个tag可显示的地方 * @protected */ _moveViewToShow: function (tagObj) { var o = this.options, self = this; var conWidth = this.tagContainer.width(), tagWidth = this.tagWrap.width(); if (tagObj && tagObj.length > 0) { if (this.editComp.outerWidth() > this.options.minWidth4Edit) { return; } var wrapLeft = this.tagWrap.offset().left;//tagWrap层左距 var conLeft = this.tagContainer.offset().left;//tagContainer层左距 var conDis = wrapLeft - conLeft; var objWidth = tagObj.width(); var target = conLeft + conWidth/2 - objWidth/2; while (this.startTagIdx >= 0 && tagObj.offset().left < target) { this._createTagFromText(this.text[this.startTagIdx]).prependTo(this.tagWrap); this.startTagIdx --; } var pos = tagObj.offset().left - target; tagWidth = this.tagWrap.width(); if(pos < 0){ pos = "-="+Math.max(pos, conDis); }else{ pos = "-="+Math.min(pos, tagWidth - conWidth + conDis); } } else { pos = Math.min(conWidth - tagWidth, 0); } this.tagWrap.animate({ left: pos }, o.animateSpeed); }, /** * EditComp的按键事件扩展,ENTER,LEFT,BACKSPACE * @private */ _onKeyDown: function (e) { var k = e.keyCode, self = e.data; if (k == FR.keyCode.ENTER) { if (this.value == "") { self.collapse(); } else { self._appendTagFromInput(this.value); self.editComp.val(""); self._editCompBlur(); } e.stopEvent(); } else if (k == FR.keyCode.LEFT) { if (this.value == "" && self.tagWrap.children().length > 0) { var tagClz = self.options.tagBaseClass; self._setTagSelect($('.' + tagClz + '-tag:last', self.tagWrap)); self.editComp.blur(); e.stopEvent(); } } else if (k == FR.keyCode.BACKSPACE) { if (this.value == "" && self.tagWrap.children().length > 0) { var tagClz = self.options.tagBaseClass; var $lastTag = $('.' + tagClz + '-tag:last', self.tagWrap); self._removeTag($lastTag, true); e.stopEvent(); } } FR.CheckBoxEditor.superclass._onKeyDown.apply(this, arguments); }, __makeSureInputValueInResList: function() { if (this.searchText == undefined) { return; } var t = this.searchText; var arr = t.split(/[,;,;]/); var endSymbol = t.endWith(',') || t.endWith(';') || t.endWith(',') || t.endWith(';'); if (!endSymbol) { return; } for (var i=0; i<arr.length; i++) { if (arr[i] != "") { this._checkAndAddTag(arr[i]); this.fireEvent(FR.Events.AFTEREDIT); break; } } }, _checkAndAddTag: function(text) { if (FR.isEmpty(text) || text == "") { return; } this.searchText = text; FR.CheckBoxEditor.superclass.__makeSureInputValueInResList.apply(this, arguments); if (this.inList || this.options.customData) { if (this.text == undefined) { this.text = []; } if ($.inArray(text, this.text) === -1) { this._pushTagData(text); this._addResultTag(text); this.searchText = null; this.editComp.val(""); var checkArr = $.grep(this.ck_el_array, function (ck_el) { return ck_el.getText() == text; }) if (checkArr && checkArr[0]) { checkArr[0].changeBoxState(true); } this.collapse(); this.options.need2BuildList = true; this.editComp.focus(); } } else { FR.Msg.toast('No custom value allowed'); this.editComp.val(text); } }, _addResultTag: function(txt) { this.tagWrap.append(this._createTagFromText(txt)); this._modifyTagPosition(); }, /** * 移除不符合规则的提示样式 */ validateCss: function () { this.editComp.removeClass('fr-trigger-invalid'); this.editComp.removeClass('fr-trigger-text-invalid'); this.editComp.removeAttr('title'); }, /** * 显示不符合规则的提示样式 */ invalidateCss: function () { this.editComp.addClass('fr-trigger-invalid'); this.editComp.addClass('fr-trigger-text-invalid'); this.editComp.attr('title', this.getErrorMsg()); }, startEditing: function () { FR.TagCheckBoxEditor.superclass.startEditing.apply(this, arguments); this._modifyTagPosition(); }, reset: function () { FR.TagCheckBoxEditor.superclass.reset.apply(this, arguments); this.inAllSelectModel = false; this.tagContainer && this.tagContainer.remove(); delete this.tagContainer; this._initTagContainer(); if(this.options.watermark){ this.removeWaterMark(); this.setWaterMark(); } } }); $.shortcut("tagcombocheckbox", FR.TagCheckBoxEditor);