forked from fanruan/fineui
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
365 lines
12 KiB
365 lines
12 KiB
/** |
|
* |
|
* 可调整列宽的grid表格 |
|
* |
|
* Created by GUY on 2016/1/12. |
|
* @class BI.ResizableTable |
|
* @extends BI.Widget |
|
*/ |
|
BI.ResizableTable = BI.inherit(BI.Widget, { |
|
_defaultConfig: function () { |
|
return BI.extend(BI.ResizableTable.superclass._defaultConfig.apply(this, arguments), { |
|
baseCls: "bi-resizable-table", |
|
el: { |
|
type: "bi.grid_table" |
|
}, |
|
isNeedFreeze: false, |
|
isNeedResize: true, |
|
isResizeAdapt: false, |
|
headerRowSize: 25, |
|
rowSize: 25, |
|
isNeedMerge: true, // 是否需要合并单元格 |
|
mergeCols: [], |
|
mergeRule: BI.emptyFn, |
|
columnSize: [], |
|
minColumnSize: [], |
|
maxColumnSize: [], |
|
freezeCols: [], |
|
header: [], |
|
items: [], |
|
regionColumnSize: [] |
|
}); |
|
}, |
|
|
|
_init: function () { |
|
BI.ResizableTable.superclass._init.apply(this, arguments); |
|
var self = this, o = this.options; |
|
this.resizer = BI.createWidget({ |
|
type: "bi.layout", |
|
cls: "resizable-table-resizer", |
|
invisible: true, |
|
width: 2 |
|
}); |
|
this.regionResizerHandler = this._createResizerHandler(); |
|
this.table = BI.createWidget(o.el, { |
|
type: "bi.grid_table", |
|
element: this, |
|
width: o.width, |
|
height: o.height, |
|
headerRowSize: o.headerRowSize, |
|
rowSize: o.rowSize, |
|
columnSize: o.columnSize, |
|
|
|
isNeedFreeze: o.isNeedFreeze, |
|
freezeCols: o.freezeCols, |
|
isNeedMerge: o.isNeedMerge, |
|
mergeCols: o.mergeCols, |
|
mergeRule: BI.bind(this._mergeRule, this), |
|
|
|
header: this._formatHeader(o.header), |
|
items: o.items, |
|
regionColumnSize: o.regionColumnSize |
|
}); |
|
this.table.on(BI.Table.EVENT_TABLE_SCROLL, function () { |
|
self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); |
|
}); |
|
BI.createWidget({ |
|
type: "bi.absolute", |
|
element: this, |
|
items: [{ |
|
el: this.regionResizerHandler, |
|
left: 0, |
|
top: 0, |
|
bottom: 0 |
|
}, { |
|
el: this.resizer, |
|
left: 0, |
|
top: 0 |
|
}] |
|
}); |
|
this._populate(); |
|
}, |
|
|
|
_mergeRule: function (row1, row2) { |
|
var o = this.options; |
|
if (row1.type === "bi.resizable_table_cell") { |
|
row1 = row1.cell; |
|
} |
|
if (row2.type === "bi.resizable_table_cell") { |
|
row2 = row2.cell; |
|
} |
|
return o.mergeRule(row1, row2); |
|
}, |
|
|
|
_createResizerHandler: function () { |
|
var self = this, o = this.options; |
|
var regionResizerHandler = BI.createWidget({ |
|
type: "bi.absolute", |
|
cls: "resizable-table-region-resizer", |
|
invisible: true, |
|
width: 6, |
|
items: [{ |
|
el: { |
|
type: "bi.layout", |
|
width: 2, |
|
cls: "resizable-table-region-resizer-knob" |
|
}, |
|
left: 2, |
|
top: 0, |
|
bottom: 0 |
|
}] |
|
}); |
|
var size = 0, offset = 0, defaultSize = 0, start = false; |
|
var mouseMoveTracker = new BI.MouseMoveTracker(function (deltaX, deltaY) { |
|
if (mouseMoveTracker.isDragging()) { |
|
start = true; |
|
offset += deltaX; |
|
size = BI.clamp(defaultSize + offset, 30, o.width - 40); |
|
|
|
self.regionResizerHandler.element.addClass("dragging"); |
|
self._setRegionResizerHandlerPosition(size - 3, 0); |
|
} |
|
|
|
}, function () { |
|
if (start === true) { |
|
o.regionColumnSize[0] = BI.clamp(size, 30, o.width - 40); |
|
self.table.setRegionColumnSize(o.regionColumnSize); |
|
if (o.isResizeAdapt === true) { |
|
var freezeColumnSize = self._getFreezeColumnSize(); |
|
o.columnSize[self._getFreezeColLength() - 1] += o.regionColumnSize[0] - freezeColumnSize; |
|
self.table.setColumnSize(o.columnSize); |
|
} |
|
// self.table.populate(); |
|
self._populate(); |
|
self.regionResizerHandler.element.removeClass("dragging"); |
|
self.fireEvent(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE); |
|
start = false; |
|
} |
|
mouseMoveTracker.releaseMouseMoves(); |
|
}, document); |
|
regionResizerHandler.element.on("mousedown", function (event) { |
|
defaultSize = size = self._getRegionSize(); |
|
offset = 0; |
|
self._setResizerPosition(0, 0); |
|
mouseMoveTracker.captureMouseMoves(event); |
|
}); |
|
return regionResizerHandler; |
|
}, |
|
|
|
_setResizerPosition: function (left, top) { |
|
this.resizer.element.css({ |
|
left: left + "px", |
|
top: top + "px" |
|
}); |
|
}, |
|
|
|
_setRegionResizerHandlerPosition: function (left, top) { |
|
this.regionResizerHandler.element.css({ |
|
left: left + "px", |
|
top: top + "px" |
|
}); |
|
}, |
|
|
|
_getRegionSize: function () { |
|
var o = this.options; |
|
var regionSize = o.regionColumnSize[0] || 0; |
|
if (o.isNeedFreeze === false || o.freezeCols.length === 0) { |
|
return 0; |
|
} |
|
if (!regionSize) { |
|
BI.each(o.freezeCols, function (i, col) { |
|
regionSize += o.columnSize[col]; |
|
}); |
|
} |
|
return regionSize; |
|
}, |
|
|
|
_getRegionRowSize: function () { |
|
var o = this.options; |
|
return [o.header.length * o.headerRowSize, |
|
Math.min(o.height - o.header.length * o.headerRowSize, o.items.length * o.rowSize)]; |
|
}, |
|
|
|
_getFreezeColLength: function () { |
|
var o = this.options; |
|
return o.isNeedFreeze === true ? BI.clamp(o.freezeCols.length, 0, o.columnSize.length) : 0; |
|
}, |
|
|
|
_getFreezeColumnSize: function () { |
|
var columnSize = this.options.columnSize; |
|
var sum = 0; |
|
for (var i = 0, len = this._getFreezeColLength(); i < len; i++) { |
|
sum += columnSize[i]; |
|
} |
|
return sum; |
|
}, |
|
|
|
_getResizerLeft: function (j) { |
|
var left = 0; |
|
var columnSize = this.options.columnSize; |
|
var freezeColLength = this._getFreezeColLength(); |
|
for (var i = (j >= freezeColLength ? freezeColLength : 0); i < j; i++) { |
|
left += columnSize[i] || 0; |
|
} |
|
if (j >= freezeColLength) { |
|
left += this.table.getRegionSize(); |
|
left -= this.table.getRightHorizontalScroll(); |
|
} else { |
|
left -= this.table.getLeftHorizontalScroll(); |
|
} |
|
return left; |
|
}, |
|
|
|
_formatHeader: function (header) { |
|
var self = this, o = this.options; |
|
var result = []; |
|
var resize = function (j, size) { |
|
self.resizer.setVisible(true); |
|
var height = o.headerRowSize + self._getRegionRowSize()[1]; |
|
self.resizer.setHeight(height); |
|
// TODO 不知道为什么加入这段代码会使得列宽调整出问题 |
|
// if (o.minColumnSize[j]) { |
|
// if (size === o.minColumnSize[j]) { |
|
// self.resizer.element.addClass("suitable"); |
|
// } else { |
|
// self.resizer.element.removeClass("suitable"); |
|
// } |
|
// } |
|
self._setResizerPosition(self._getResizerLeft(j) + size, (o.header.length - 1) * o.headerRowSize); |
|
}; |
|
var stop = function (j, size) { |
|
self.resizer.setVisible(false); |
|
var columnSize = o.columnSize.slice(); |
|
columnSize[j] = size; |
|
o.columnSize = columnSize; |
|
self.table.setColumnSize(columnSize); |
|
// self.table.populate(); |
|
self._populate(); |
|
self.fireEvent(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE); |
|
}; |
|
BI.each(header, function (i, cols) { |
|
if (i === header.length - 1) { |
|
result[i] = []; |
|
BI.each(cols, function (j, col) { |
|
if (j === self._getFreezeColLength() - 1 || j === cols.length - 1) { |
|
result[i][j] = col; |
|
} else { |
|
result[i][j] = { |
|
type: "bi.resizable_table_cell", |
|
cell: col, |
|
suitableSize: o.minColumnSize[j], |
|
maxSize: o.maxColumnSize[j], |
|
resize: BI.bind(resize, null, j), |
|
stop: BI.bind(stop, null, j) |
|
}; |
|
if (o.isNeedMerge) { |
|
var r = i; |
|
while (r > 0 && self._mergeRule(result[r][j], result[r - 1][j])) { |
|
result[r - 1][j] = { |
|
type: "bi.resizable_table_cell", |
|
cell: result[r - 1][j], |
|
suitableSize: o.minColumnSize[j], |
|
maxSize: o.maxColumnSize[j], |
|
resize: BI.bind(resize, null, j), |
|
stop: BI.bind(stop, null, j) |
|
}; |
|
r--; |
|
} |
|
} |
|
} |
|
}); |
|
} else { |
|
result.push(cols); |
|
} |
|
}); |
|
return result; |
|
}, |
|
|
|
_populate: function () { |
|
var o = this.options; |
|
var regionSize = this._getRegionSize(); |
|
if (regionSize > 0) { |
|
this.regionResizerHandler.setVisible(true); |
|
this._setRegionResizerHandlerPosition(regionSize - 3, 0); |
|
} else { |
|
this.regionResizerHandler.setVisible(false); |
|
} |
|
}, |
|
|
|
setWidth: function (width) { |
|
BI.ResizableTable.superclass.setWidth.apply(this, arguments); |
|
this.table.setWidth(width); |
|
}, |
|
|
|
setHeight: function (height) { |
|
BI.ResizableTable.superclass.setHeight.apply(this, arguments); |
|
this.table.setHeight(height); |
|
}, |
|
|
|
setVerticalScroll: function (scrollTop) { |
|
this.table.setVerticalScroll(scrollTop); |
|
}, |
|
|
|
setLeftHorizontalScroll: function (scrollLeft) { |
|
this.table.setLeftHorizontalScroll(scrollLeft); |
|
}, |
|
|
|
setRightHorizontalScroll: function (scrollLeft) { |
|
this.table.setRightHorizontalScroll(scrollLeft); |
|
}, |
|
|
|
setColumnSize: function (columnSize) { |
|
this.options.columnSize = columnSize; |
|
this.table.setColumnSize(columnSize); |
|
}, |
|
|
|
getColumnSize: function () { |
|
return this.table.getColumnSize(); |
|
}, |
|
|
|
setRegionColumnSize: function (columnSize) { |
|
this.options.regionColumnSize = columnSize; |
|
this.table.setRegionColumnSize(columnSize); |
|
}, |
|
|
|
getRegionColumnSize: function () { |
|
return this.table.getRegionColumnSize(); |
|
}, |
|
|
|
getVerticalScroll: function () { |
|
return this.table.getVerticalScroll(); |
|
}, |
|
|
|
getLeftHorizontalScroll: function () { |
|
return this.table.getLeftHorizontalScroll(); |
|
}, |
|
|
|
getRightHorizontalScroll: function () { |
|
return this.table.getRightHorizontalScroll(); |
|
}, |
|
|
|
attr: function () { |
|
BI.ResizableTable.superclass.attr.apply(this, arguments); |
|
this.table.attr.apply(this.table, arguments); |
|
}, |
|
|
|
restore: function () { |
|
this.table.restore(); |
|
}, |
|
|
|
populate: function (items, header) { |
|
if (items) { |
|
this.options.items = items; |
|
} |
|
if (header) { |
|
this.options.header = header; |
|
if (this.options.isNeedResize) { |
|
header = this._formatHeader(header); |
|
} |
|
} |
|
this.table.populate(items, header); |
|
this._populate(); |
|
} |
|
}); |
|
|
|
BI.shortcut("bi.resizable_table", BI.ResizableTable); |