(function ($) { /** * 多标签容器。在多sheet报表中被使用到,如果需要使用代码控制sheet的跳转、展现等可以使用次类的方法。 * @class FR.TabPane * @extends FR.Widget * * @cfg {JSON} options 配置属性 * @cfg {Number} [options.width='100%'] 容器宽度 * @cfg {Number} [options.height='100%'] 容器高度 * @cfg {Number} [options.active=0] 当前活跃的tab索引 * @cfg {'top'/'bottom'} [options.tabPosition='top'] tab控制器所在的位置,可以是底部或者顶部 * @cfg {Number} [options.tabHeight=22] tab控制器的高度 * @cfg {Boolean} [options.noControl=false] 是否不需要tab控制器 * @cfg {Boolean} [options.defaultActiveIndex=0] 初始化完成后默认激活的tab索引 * @cfg {Array} options.items tab容器的子组件 */ FR.TabPane = FR.extend(FR.Widget, /**@class FR.TabPane*/{ _defaultConfig: function () { return $.extend(FR.TabPane.superclass._defaultConfig.apply(), { baseCls: "fr-tabpane", width: "100%", height: "100%", active: 0, tabPosition: "top", //tab所在位置,上|下 tabHeight: 22, noControl: false, //是否不需要tab控制按钮 items: [], defaultActiveIndex: 0 //初始化后默认被激活的tab的位置索引 }); }, _init: function () { FR.TabPane.superclass._init.apply(this, arguments); var opts = this.options; this.element.css({ width: opts.width, height: opts.height }); //生成配置信息 var borderLayoutConfig = this._createConfig4TabPaneConfig(); //整体布局 var borderLayout = new FR.BorderLayout(borderLayoutConfig); borderLayout.doLayout(); //生成所有的tab标签 this.wrapWidth = 0; //记录所有标签总宽度 this._initTabs(); //选中默认tab if (this.tabBtns[opts.defaultActiveIndex]) { this.tabBtns[opts.defaultActiveIndex].setSelected(); } this.isMoving = false; this.activeTabIndex = opts.defaultActiveIndex; //当前被激活tab的位置索引 var self = this; this.tabsContent.parent().addClass(opts.baseCls + '-tabscontent-bg'); $(window).resize( function () { self.fireEvent(FR.Events.SCROLLCHANGE, self, self.activeTabIndex); } ); }, /** * 生成tabPane控件整体布局的配置信息 * @private * @returns {*} 返回配置信息 */ _createConfig4TabPaneConfig: function () { var opts = this.options; var tabPos = opts.tabPosition; var contentCls = opts.baseCls + '-content'; //tab内容层-tabPaneContent this.tabPaneContent = $('<div></div>').addClass(contentCls).addClass(contentCls + '-' + tabPos); //tab标签层-配置信息 var tabControlConfig = this._createConfig4TabControl(); var borderLayoutConfig = { renderEl: this.element, items: [ { region: "center", el: this.tabPaneContent }, { height: opts.tabHeight, region: tabPos == 'top' ? 'north' : 'south', el: tabControlConfig } ] }; return borderLayoutConfig; }, /** * 生成标签和控制按钮的配置信息 * @returns {JSON} 返回配置信息 * @private */ _createConfig4TabControl: function () { var self = this, opts = this.options; this.tabsContent = $('<div/>').addClass(opts.baseCls + '-tabscontent') .addClass(opts.baseCls + '-tabscontent-' + opts.tabPosition); var items = [ { region: "center", el: $('<div/>').append(this.tabsContent) } ]; //不需要tab控制按钮就不生成 if (!this.options.noControl) { items.unshift({ region: "west", el: { type: 'horizontal', widgetName: 'controlbuttons', baseCls: 'fr-tabpane-controlbuttons', alignment: 'center', hgap: 3, vgap: 2, items: [ { el: this._createTabControlBtn('arrow1', function () { if(self.isMoving){ return; } self._moveViewToPos('start'); //移动到第一个tab }), width: 13 }, { el: this._createTabControlBtn('arrow2', function () { if(self.isMoving){ return; } var distance = self.stepDis; var realDis = self.tabsContent.offset().left - self.tabsWrap.offset().left; distance = Math.min(distance,realDis); self._moveViewToPos(distance); }), width: 13 }, { el: this._createTabControlBtn('arrow3', function () { if(self.isMoving){ return; } var distance = self.stepDis; var realDis = self.tabsWrap.offset().left + self.wrapWidth - self.tabsContent.offset().left - self.tabsContent.width(); distance = Math.min(distance,realDis); distance = distance < 0?0:distance; self._moveViewToPos(- distance); }), width: 13 }, { el: this._createTabControlBtn('arrow4', function () { if(self.isMoving){ return; } self._moveViewToPos('end'); //移动到最后一个tab }), width: 13 } ] }, width: 72 }); } var tabControlConfig = { type: "border", items: items }; return tabControlConfig; }, /** * 生成tab控制按钮 * @param {String} name 样式类名 * @param {Function} handler 点击事件 * @returns {jQuery} 返回按钮的DOM对象 * @private */ _createTabControlBtn: function (name, handler) { var iconbtn = new FR.IconButton({ type: "iconbutton", baseClass: 'fr-edit-sheetcontrol-icon-box', handler: handler }); $('<div>').addClass('fr-edit-sheetcontrol-icon-' + name).appendTo(iconbtn.element); return iconbtn.element; }, /** * 初始化所有的tab * @private */ _initTabs: function () { var opts = this.options; this.tabBtns = []; //用来装载所有的tab标签并用于平移 this.tabsWrap = $('<ul/>').addClass(opts.baseCls + '-tabswrap').appendTo(this.tabsContent); if (!opts.items) { return; } if (!opts.tabs) { opts.tabs = []; } for (var i = 0; i < opts.items.length; i++) { this._addTabContent(opts.items[i]); this._addTabTag(i, opts.items[i]); } }, /** * 添加一个tab的内容 * @param {jQuery} item tab对象 * @private */ _addTabContent: function (item) { var tabs = this.options.tabs; if (item.tabContent) { var widget = FR.createWidget(item.tabContent); widget.element.appendTo(this.tabPaneContent); item.content = widget.element; } else { var content = $('<div/>').addClass("html-content").appendTo(this.tabPaneContent); item.content = content; } item.content.hide(); tabs.push(item); }, /** * 添加一个tab的标签 * @param {Number} index 位置索引 * @param {jQuery} item tab对象 * @private */ _addTabTag: function (index, item) { var self = this, items = this.options.items; //生成一个tab标签 var config = { tabPane: this, name: item.title, index: index, isFirst: index === 0, isLast: index === items.length - 1, renderEl: $('<li/>').appendTo(this.tabsWrap), tabBtns: this.tabBtns, handler: function () { if (self.activeTabIndex >= 0) { self.options.tabs[self.activeTabIndex].content.hide(); } self.activeTabIndex = index; if (self.options.tabs[index].content) { self.options.tabs[index].content.show(); } self.showSheetContent(self.activeTabIndex); self._moveViewToShow(self.activeTabIndex); } }; var sheetBtn = new FR.SheetButton(config); this.tabBtns.push(sheetBtn); this.wrapWidth += sheetBtn.getWidth(); this.stepDis = this.wrapWidth/this.tabBtns.length; //取平均数作为固定移动步长 }, /** * 使指定位置的tab移动到可完整显示 * @param {Number} tabIndex tab的位置索引 * @private */ _moveViewToShow: function (tabIndex) { var tabObj = this.tabBtns[tabIndex].element; //当前选中DOM var view = this.tabsWrap; //滑动主体DOM var bounds = this.tabsContent; //外边界DOM var boundsLeft = bounds.offset().left; var boundsRight = boundsLeft + bounds.width(); var viewLeft = view.offset().left; var viewRight = viewLeft + this.wrapWidth; var tabLeft = tabObj.offset().left; var tabRight = tabLeft + tabObj.width(); var dis = tabObj.width(); //理应移动的距离 var realDis = 0; //实际可移动的距离 if (tabLeft < boundsLeft) { //左出界,右移 + realDis = boundsLeft - viewLeft; realDis = Math.min(realDis, dis); } else if (tabRight > boundsRight) { //右出界,左移 - realDis = boundsRight - viewRight; realDis = Math.max(realDis, -dis); } else { return; } this._moveViewToPos(realDis); }, /** * 所有tab移动一段距离或移动到某个位置 * @param {Number/String/'start'/'end'} distance 距离,'start'表示移动到第一个tab标签,'end'表示移动到最后一个tab标签 * @private */ _moveViewToPos: function (distance) { var self = this; this.isMoving = true; if (distance == 'start') { //表示回到原点 this.tabsWrap.animate({ 'left': '0' }, 'fast', function(){ self.isMoving = false; }); } else if (distance == 'end') { var pos = this.tabsContent.width() - this.wrapWidth; if(pos > 0){ pos = 0; } this.tabsWrap.animate({ 'left': pos }, 'fast', function(){ self.isMoving = false; }); } else { this.tabsWrap.animate({ 'left': '+=' + distance }, 'fast', function(){ self.isMoving = false; }); } }, /** * 显示指定位置索引的sheet内容 * @param {Number} position 位置索引 */ showSheetContent: function (position) { this.fireEvent(FR.Events.TABCHANGESTART, this, position); this.fireEvent(FR.Events.TABCHANGE, this, position); this.fireEvent(FR.Events.SCROLLCHANGE, this, position); }, doResize: function (give) { this.element.css({ width: give.width, height: give.height }); }, /** * 选中指定位置索引的Tab,并显示Tab内容 * @param {Number} index 位置索引 * @return {Boolean} 返回选择是否成功 */ selectTabAt: function(index){ if(index >= 0){ this.tabBtns[index].setSelected(); return true; } return false; }, /** * 获取指定位置索引的Tab的内容 * @param {Number} index 要获取的tab的索引 * @return {JSON} 返回Tab对象,其content属性表示Tab内容的DOM对象 */ getTabByIndex: function(index){ if(index >=0){ return this.options.tabs[index]; } return {}; }, /** * 获取指定Tab标签名的Tab内容 * @param {String} name Tab标签名 * @return {JSON} 返回第一个与所给标签名匹配的Tab对象 */ getTabByName: function(name){ if(!FR.isEmpty(name)){ for(var i = 0;i< this.tabBtns.length;i++){ if(this.tabBtns[i].name == name){ return this.options.tabs[i]; } } } return {}; }, /** * 获取当前所选中的tab的位置索引 * @returns {Number} 返回位置索引 */ getSelectedIndex: function(){ return this.activeTabIndex; } }); $.shortcut("tabpane", FR.TabPane); /** * Tab按钮 * @class FR.SheetButton * @extends FR.Widget * @private */ FR.SheetButton = FR.extend(FR.Widget, /**@class FR.SheetButton*/{ _defaultConfig: function () { return $.extend(FR.SheetButton.superclass._defaultConfig.apply(), { tabPane: null, //传递进来的FR.TabPane对象 tabBtns: [], //传递进来的tabBtns属性 isFirst: false, //是否是第一个标签 isLast: false, //是否是最后一个标签 index: 0, //标签位置索引 minWidth: 60, //最小宽度 handler: null, disabled: false, name: '', containerCls4btn: "fr-sheetbutton-container", intersectCls4btn: "fr-sheetbutton-intersect", firstPartCls4btn: "fr-sheetbutton-firstpart", middlePartCls4btn: "fr-sheetbutton-middlepart", thirdPartCls4btn: "fr-sheetbutton-thirdpart", endPartCls4btn: "fr-sheetbutton-endpart", button_class_prefix: "fr-sheet-icon-", button_closebtn_class: "fr-sheetbutton-closebutton" }); }, _init: function () { FR.SheetButton.superclass._init.apply(this, arguments); var o = this.options, self = this; var tabPos = o.tabPane.options.tabPosition; if (tabPos == 'top') { o.firstPartCls4btn += '-' + tabPos; o.middlePartCls4btn += '-' + tabPos; o.thirdPartCls4btn += '-' + tabPos; o.endPartCls4btn += '-' + tabPos; } this.element.addClass(o.containerCls4btn).attr("title", o.name); this._createTabBtnByName(o.name); //点击事件 if ($.isFunction(o.handler)) { this.on(FR.Events.CLICK, o.handler.createDelegate(o.scope || this)); } this.element.click(function () { if (self.isEnabled()) { self.setSelected(); } }); this.width = this.element.width(); this.fireEvent(FR.Events.AFTERINIT); }, /** * 生成标签按钮 * @param {String} name tab标签的文字内容 * @private */ _createTabBtnByName: function (name) { var o = this.options; var li = this.element; if (this.options.isFirst) { li.head = $('<span/>').addClass(o.firstPartCls4btn).appendTo(li); //首 } li.middle = $('<span/>').addClass(o.middlePartCls4btn).text(name).appendTo(li); //中部-文字 //设置文字部分最小宽度 if(li.middle.width() < o.minWidth){ li.middle.width(o.minWidth); } if (!o.isLast) { li.end = $('<span/>').addClass(o.thirdPartCls4btn).appendTo(li); //尾-交叉,非最后tab } else { li.end = $('<span/>').addClass(o.endPartCls4btn).appendTo(li); //尾-最后一个tab } }, /** * 获取当前sheet总宽度 * @returns {Number} 返回当前sheet总宽度 */ getWidth: function(){ return this.width; }, /** * 选中当前tab */ setSelected: function () { var o = this.options; if (this.isActive()) { return; } this.setActiveState(true); var activeIndex = o.tabPane.activeTabIndex; if (activeIndex >= 0 && activeIndex !== o.index) { o.tabBtns[activeIndex].setActiveState(false); } this.fireEvent(FR.Events.CLICK); }, /** * 设置该tab的激活状态 * @param {Boolean} state 是否激活 */ setActiveState: function (state) { var o = this.options; this.isActiveState = state; if (state) { this.element.addClass(o.containerCls4btn + "-active"); if (!o.isFirst) { o.tabBtns[o.index - 1].element.addClass(o.intersectCls4btn); } } else { this.element.removeClass(o.containerCls4btn + "-active"); if (!o.isFirst) { o.tabBtns[o.index - 1].element.removeClass(o.intersectCls4btn); } } }, /** * 设置该tab的校验状态 * @param {Boolean} isValid 是否符合校验规则 */ setValidState: function(isValid){ var $dom = this.element, opts = this.options; var curIdx = opts.index; if(!isValid){ if(opts.isFirst){ $dom.head.switchClass(opts.firstPartCls4btn + '-invalidate'); }else{ var pre = opts.tabPane.tabBtns[curIdx - 1]; if(pre.isValid()){ pre.element.end.switchClass(opts.thirdPartCls4btn + '-invalidate-style3'); }else{ pre.element.end.switchClass(opts.thirdPartCls4btn + '-invalidate-style2'); } } $dom.middle.switchClass(opts.middlePartCls4btn + '-invalidate'); if(opts.isLast){ $dom.end.switchClass(opts.endPartCls4btn + '-invalidate'); }else{ if(opts.tabPane.tabBtns[curIdx + 1].isValid()){ $dom.end.switchClass(opts.thirdPartCls4btn + '-invalidate'); }else if(opts.tabPane.tabBtns[curIdx - 1].isValid()){ $dom.end.switchClass(opts.thirdPartCls4btn + '-invalidate-style2'); } } }else{ if(opts.isFirst){ $dom.head.switchClass(opts.firstPartCls4btn); }else{ var pre = opts.tabPane.tabBtns[curIdx - 1]; if(pre.isValid()){ pre.element.end.switchClass(opts.thirdPartCls4btn); }else{ pre.element.end.switchClass(opts.thirdPartCls4btn + '-invalidate'); } } $dom.middle.switchClass(opts.middlePartCls4btn); if(opts.isLast){ $dom.end.switchClass(opts.endPartCls4btn); }else{ if(opts.tabPane.tabBtns[curIdx + 1].isValid()){ $dom.end.switchClass(opts.thirdPartCls4btn); }else{ $dom.end.switchClass(opts.thirdPartCls4btn + '-invalidate-style3'); } } } this.isValidState = isValid; }, /** * 判断该tab是否符合校验 * @returns {Boolean} 返回当前tab是否符合校验 */ isValid: function(){ return this.isValidState !== false; }, /** * 判断该tab是否为激活状态 * @returns {Boolean} 返回当前tab是否为激活状态 */ isActive: function () { return this.isActiveState === true; }, destroy: function () { this.element.empty(); } }); $.shortcut("sheetbutton", FR.SheetButton); })(jQuery);