(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);