blob: 022c82959863bc995328cd5be3cd4f0d0e1480b2 [file] [log] [blame]
/**
* @file Data table
* @author sushuang(sushuang@baidu.com)
*/
define(function (require) {
var $ = require('jquery');
var Component = require('dt/ui/Component');
var dataTableProcessor = require('./dataTableProcessor');
var EditorData = require('./EditorData');
var Handsontable = require('handsontable');
// Constants
var ROW_COL_HEAD_ACTIVE_CLASS = 'rchead-highlight';
var SELECTOR_DATA_TABLE = '.ecdoc-sprsht-ht';
/**
* @class
* @extends dt/ui/Component
*/
var DataTable = Component.extend({
_define: {
tpl: require('tpl!./spreadsheet.tpl.html'),
tplTarget: 'DataTable',
css: 'ecdoc-sprsht-datatable',
viewModel: function () {
return {
jsDataOb: null // 外部传入
};
}
},
/**
* @public
*/
_init: function () {
/**
* handsontable 实例
*/
this._htIns = null;
// 行列选中,在handsontable尚未找到设置或API
this._createHandsontable();
},
/**
* @public
*/
clearContent: function () {
if (this._htIns) {
this._htIns.dtEditorData.clear();
}
},
/**
* @public
*/
refresh: function () {
if (this._htIns) {
this._htIns.render();
}
},
/**
* @public
* @param {string} target 'lt', 'rb', 'l', 'r', 't', 'b'
*/
scrollViewportTo: function (target) {
var htIns = this._htIns;
var dataWindow = htIns.dtEditorData.getDataWindowSize();
var maxCol = Math.max(0, dataWindow.colCount - 1);
var maxRow = Math.max(0, dataWindow.rowCount - 1);
var mapping = {
lt: [0, 0],
rb: [maxRow, maxCol],
l: [null, 0],
r: [null, maxCol],
t: [0, null],
b: [maxRow, null]
};
htIns.scrollViewportTo.apply(htIns, mapping[target]);
},
/**
* @override
*/
_dispose: function () {
// 现在没有会dispose的场景,不实现
},
/**
* @private
*/
_createHandsontable: function () {
var options = this._makeHandsontableOptions();
if (!options.data) {
// 初始数据
options.data = [[]];
}
var $dataTable = this.$el(
'dataTable', this.$el().find(SELECTOR_DATA_TABLE)
);
var htIns = this._htIns = new Handsontable($dataTable[0], options);
// var htIns = this._htIns = $dataTable.handsontable('getInstance');
// 直接使用htIns.dtEditorData即可引用editorData实例。
// 加dt前缀是防止与handsontable自身的属性冲突。
htIns.dtEditorData = new EditorData(htIns);
// Enhance features for handsontable
$dataTable.on(
'click',
'table.htCore thead th',
function (event) {
selectCol(htIns, event.currentTarget);
}
);
$dataTable.on(
'click',
'table.htCore tbody th',
function (event) {
selectRow(htIns, event.currentTarget);
}
);
this._viewModel().jsDataOb.bindDataTable(htIns);
},
/**
* @inner
*/
_makeHandsontableOptions: function () {
var that = this;
return {
cells: function (row, col) {
// 此函数将在循环体中被频繁调用。(每次更改handsontable时调用)
if (that._htIns) {
dataTableProcessor.processCell(
this, that._viewModel().jsDataOb, row, col
);
}
// this.readOnly = true;
},
afterChange: function (change, source) {
// source可为:
// "alter", "empty", "edit", "populateFromArray", "loadData", "autofill", "paste"
// 其中 alter, empty目前不知含义
// 原则:只有loadData认为是不用执行持久化
if (source === 'loadData') {
return;
}
refreshJSData();
},
afterCreateRow: refreshJSData,
afterCreateCol: refreshJSData,
afterRemoveRow: refreshJSData,
afterRemoveCol: refreshJSData,
afterSelection: function () {
refreshRowColHeadHighlight(this.view.wt);
},
afterDeselect: function () {
clearRowColHeadHighlight(this.view.wt);
},
afterRender: function () {
refreshRowColHeadHighlight(this.view.wt);
},
minSpareRows: 1,
minSpareCols: 1,
rowHeaders: true,
colHeaders: true,
contextMenu: true,
minRows: 50,
minCols: 15,
stretchH: 'last', // 设为'all'时,列拖拽改变宽度时体验稍有问题。
// width: function //??
// height: function //??
trimWhitespace: true,
manualColumnResize: true,
manualColumnMove: false,
fillHandle: true,
undo: true,
outsideClickDeselects: true,
enterBeginsEditing: true,
autoWrapCol: false,
autoWrapRow: false,
copyRowsLimit: 600000, // 此设定是否合理??
copyColsLimit: 600000, // 此设定是否合理??
pasteMode: 'overwrite',
columnSorting: false,
persistentState: false
};
// 注意这个方法会频繁调用,所以在processor中统一使用throttle。
function refreshJSData() {
that._viewModel().jsDataOb.fillJSDataByDataTable();
}
}
});
// 增补handsontable功能,点击col head 能够选择一列
function selectCol(htIns, rowHead) {
var wtTable = htIns.view.wt.wtTable;
var ths = wtTable.THEAD.childNodes[0].childNodes;
var rowCount = htIns.countRows();
for (var i = 0, len = ths.length; i < len; i++) {
if (rowHead === ths[i]) {
var srcColIndex = wtTable.columnFilter.visibleRowHeadedColumnToSourceColumn(i);
htIns.selectCell(0, srcColIndex, rowCount - 1, srcColIndex, false);
break;
}
}
}
// 增补handsontable功能,点击row head 能够选择一行
function selectRow(htIns, colHead) {
var wtTable = htIns.view.wt.wtTable;
var trs = wtTable.TBODY.childNodes;
var colCount = htIns.countCols();
for (var i = 0, len = trs.length; i < len; i++) {
if (colHead === trs[i].childNodes[0]) {
var srcRowIndex = wtTable.rowFilter.visibleToSource(i);
htIns.selectCell(srcRowIndex, 0, srcRowIndex, colCount - 1, false);
break;
}
}
}
// 增补handsontable功能,选中时增加row col head 上的高亮
function refreshRowColHeadHighlight(wt) {
// inactive rows and cols
clearRowColHeadHighlight(wt);
var selected = getSelectedArea(wt);
var wtTable = wt.wtTable;
if (!selected) {
return;
}
// active row head
for (var i = selected.r; i <= selected.r2; i++) {
var rowHead = getRowHead(wtTable, i);
rowHead && $(rowHead).addClass(ROW_COL_HEAD_ACTIVE_CLASS);
}
// active col head
for (var i = selected.c; i <= selected.c2; i++) {
var colHead = getColHead(wtTable, i);
colHead && $(colHead).addClass(ROW_COL_HEAD_ACTIVE_CLASS);
}
}
// 清除row col head 上的高亮
function clearRowColHeadHighlight(wt) {
// inactive rows and cols
$('.' + ROW_COL_HEAD_ACTIVE_CLASS, wt.wtTable.TABLE)
.removeClass(ROW_COL_HEAD_ACTIVE_CLASS);
}
// 如果有选中,返回:{r: number, c: number, r2: number, c2: number} 保证r小于r2,c小于c2。
// 如果没有选中,返回undefined
function getSelectedArea(wt) {
var ret = {};
var tmp;
var selected = wt.selections.area.selected;
if (selected && selected.length >= 2) {
ret.r = selected[0][0];
ret.c = selected[0][1];
ret.r2 = selected[1][0];
ret.c2 = selected[1][1];
}
else {
// 如果没有选中区域的话,area中的selected无内容
selected = wt.selections.current.selected;
if (selected && selected.length >= 1) {
ret.r = selected[0][0];
ret.c = selected[0][1];
ret.r2 = ret.r;
ret.c2 = ret.c;
}
else {
return;
}
}
ret.r > ret.r2 && (tmp = ret.r, ret.r = ret.r2, ret.r2 = tmp);
ret.c > ret.c2 && (tmp = ret.c, ret.c = ret.c2, ret.c2 = tmp);
return ret;
}
// 获得col head节点
function getColHead(wtTable, c) {
if (!wtTable.isColumnBeforeViewport(c)
&& !wtTable.isColumnAfterViewport(c)
) {
return wtTable.THEAD
.childNodes[0]
.childNodes[wtTable.columnFilter.sourceColumnToVisibleRowHeadedColumn(c)];
}
}
// 获得row head节点
function getRowHead(wtTable, r) {
if (!wtTable.isRowBeforeViewport(r)
&& !wtTable.isRowAfterViewport(r)
) {
return wtTable.TBODY
.childNodes[wtTable.rowFilter.sourceToVisible(r)]
.childNodes[0];
}
}
return DataTable;
});