tabulator-tables
Version:
Interactive table generation JavaScript library
735 lines (557 loc) • 17.2 kB
JavaScript
//public row object
var CellComponent = function (cell){
this._cell = cell;
};
CellComponent.prototype.getValue = function(){
return this._cell.getValue();
};
CellComponent.prototype.getOldValue = function(){
return this._cell.getOldValue();
};
CellComponent.prototype.getElement = function(){
return this._cell.getElement();
};
CellComponent.prototype.getRow = function(){
return this._cell.row.getComponent();
};
CellComponent.prototype.getData = function(){
return this._cell.row.getData();
};
CellComponent.prototype.getField = function(){
return this._cell.column.getField();
};
CellComponent.prototype.getColumn = function(){
return this._cell.column.getComponent();
};
CellComponent.prototype.setValue = function(value, mutate){
if(typeof mutate == "undefined"){
mutate = true;
}
this._cell.setValue(value, mutate);
};
CellComponent.prototype.restoreOldValue = function(){
this._cell.setValueActual(this._cell.getOldValue());
};
CellComponent.prototype.edit = function(force){
return this._cell.edit(force);
};
CellComponent.prototype.cancelEdit = function(){
this._cell.cancelEdit();
};
CellComponent.prototype.nav = function(){
return this._cell.nav();
};
CellComponent.prototype.checkHeight = function(){
this._cell.checkHeight();
};
CellComponent.prototype.getTable = function(){
return this._cell.table;
};
CellComponent.prototype._getSelf = function(){
return this._cell;
};
var Cell = function(column, row){
this.table = column.table;
this.column = column;
this.row = row;
this.element = null;
this.value = null;
this.oldValue = null;
this.height = null;
this.width = null;
this.minWidth = null;
this.build();
};
//////////////// Setup Functions /////////////////
//generate element
Cell.prototype.build = function(){
this.generateElement();
this.setWidth();
this._configureCell();
this.setValueActual(this.column.getFieldValue(this.row.data));
};
Cell.prototype.generateElement = function(){
this.element = document.createElement('div');
this.element.className = "tabulator-cell";
this.element.setAttribute("role", "gridcell");
this.element = this.element;
};
Cell.prototype._configureCell = function(){
var self = this,
cellEvents = self.column.cellEvents,
element = self.element,
field = this.column.getField();
//set text alignment
element.style.textAlign = self.column.hozAlign;
if(field){
element.setAttribute("tabulator-field", field);
}
//add class to cell if needed
if(self.column.definition.cssClass){
var classNames = self.column.definition.cssClass.split(" ")
classNames.forEach(function(className) {
element.classList.add(className)
});
}
//update tooltip on mouse enter
if (this.table.options.tooltipGenerationMode === "hover"){
element.addEventListener("mouseenter", function(e){
self._generateTooltip();
});
}
self._bindClickEvents(cellEvents);
self._bindTouchEvents(cellEvents);
self._bindMouseEvents(cellEvents);
if(self.column.modules.edit){
self.table.modules.edit.bindEditor(self);
}
if(self.column.definition.rowHandle && self.table.options.movableRows !== false && self.table.modExists("moveRow")){
self.table.modules.moveRow.initializeCell(self);
}
//hide cell if not visible
if(!self.column.visible){
self.hide();
}
};
Cell.prototype._bindClickEvents = function(cellEvents){
var self = this,
element = self.element;
//set event bindings
if (cellEvents.cellClick || self.table.options.cellClick){
element.addEventListener("click", function(e){
var component = self.getComponent();
if(cellEvents.cellClick){
cellEvents.cellClick.call(self.table, e, component);
}
if(self.table.options.cellClick){
self.table.options.cellClick.call(self.table, e, component);
}
});
}
if (cellEvents.cellDblClick || this.table.options.cellDblClick){
element.addEventListener("dblclick", function(e){
var component = self.getComponent();
if(cellEvents.cellDblClick){
cellEvents.cellDblClick.call(self.table, e, component);
}
if(self.table.options.cellDblClick){
self.table.options.cellDblClick.call(self.table, e, component);
}
});
}else{
element.addEventListener("dblclick", function(e){
e.preventDefault();
if (document.selection) { // IE
var range = document.body.createTextRange();
range.moveToElementText(self.element);
range.select();
} else if (window.getSelection) {
var range = document.createRange();
range.selectNode(self.element);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
}
});
}
if (cellEvents.cellContext || this.table.options.cellContext){
element.addEventListener("contextmenu", function(e){
var component = self.getComponent();
if(cellEvents.cellContext){
cellEvents.cellContext.call(self.table, e, component);
}
if(self.table.options.cellContext){
self.table.options.cellContext.call(self.table, e, component);
}
});
}
};
Cell.prototype._bindMouseEvents = function(cellEvents){
var self = this,
element = self.element;
if (cellEvents.cellMouseEnter || self.table.options.cellMouseEnter){
element.addEventListener("mouseenter", function(e){
var component = self.getComponent();
if(cellEvents.cellMouseEnter){
cellEvents.cellMouseEnter.call(self.table, e, component);
}
if(self.table.options.cellMouseEnter){
self.table.options.cellMouseEnter.call(self.table, e, component);
}
});
}
if (cellEvents.cellMouseLeave || self.table.options.cellMouseLeave){
element.addEventListener("mouseleave", function(e){
var component = self.getComponent();
if(cellEvents.cellMouseLeave){
cellEvents.cellMouseLeave.call(self.table, e, component);
}
if(self.table.options.cellMouseLeave){
self.table.options.cellMouseLeave.call(self.table, e, component);
}
});
}
if (cellEvents.cellMouseOver || self.table.options.cellMouseOver){
element.addEventListener("mouseover", function(e){
var component = self.getComponent();
if(cellEvents.cellMouseOver){
cellEvents.cellMouseOver.call(self.table, e, component);
}
if(self.table.options.cellMouseOver){
self.table.options.cellMouseOver.call(self.table, e, component);
}
});
}
if (cellEvents.cellMouseOut || self.table.options.cellMouseOut){
element.addEventListener("mouseout", function(e){
var component = self.getComponent();
if(cellEvents.cellMouseOut){
cellEvents.cellMouseOut.call(self.table, e, component);
}
if(self.table.options.cellMouseOut){
self.table.options.cellMouseOut.call(self.table, e, component);
}
});
}
if (cellEvents.cellMouseMove || self.table.options.cellMouseMove){
element.addEventListener("mousemove", function(e){
var component = self.getComponent();
if(cellEvents.cellMouseMove){
cellEvents.cellMouseMove.call(self.table, e, component);
}
if(self.table.options.cellMouseMove){
self.table.options.cellMouseMove.call(self.table, e, component);
}
});
}
};
Cell.prototype._bindTouchEvents = function(cellEvents){
var self = this,
element = self.element,
dblTap, tapHold, tap;
if (cellEvents.cellTap || this.table.options.cellTap){
tap = false;
element.addEventListener("touchstart", function(e){
tap = true;
}, {passive: true});
element.addEventListener("touchend", function(e){
if(tap){
var component = self.getComponent();
if(cellEvents.cellTap){
cellEvents.cellTap.call(self.table, e, component);
}
if(self.table.options.cellTap){
self.table.options.cellTap.call(self.table, e, component);
}
}
tap = false;
});
}
if (cellEvents.cellDblTap || this.table.options.cellDblTap){
dblTap = null;
element.addEventListener("touchend", function(e){
if(dblTap){
clearTimeout(dblTap);
dblTap = null;
var component = self.getComponent();
if(cellEvents.cellDblTap){
cellEvents.cellDblTap.call(self.table, e, component);
}
if(self.table.options.cellDblTap){
self.table.options.cellDblTap.call(self.table, e, component);
}
}else{
dblTap = setTimeout(function(){
clearTimeout(dblTap);
dblTap = null;
}, 300);
}
});
}
if (cellEvents.cellTapHold || this.table.options.cellTapHold){
tapHold = null;
element.addEventListener("touchstart", function(e){
clearTimeout(tapHold);
tapHold = setTimeout(function(){
clearTimeout(tapHold);
tapHold = null;
tap = false;
var component = self.getComponent();
if(cellEvents.cellTapHold){
cellEvents.cellTapHold.call(self.table, e, component);
}
if(self.table.options.cellTapHold){
self.table.options.cellTapHold.call(self.table, e, component);
}
}, 1000);
}, {passive: true});
element.addEventListener("touchend", function(e){
clearTimeout(tapHold);
tapHold = null;
});
}
};
//generate cell contents
Cell.prototype._generateContents = function(){
var val;
if(this.table.modExists("format")){
val = this.table.modules.format.formatValue(this);
}else{
val = this.element.innerHTML = this.value;
}
switch(typeof val){
case "object":
if(val instanceof Node){
//clear previous cell contents
while(this.element.firstChild) this.element.removeChild(this.element.firstChild);
this.element.appendChild(val);
}else{
this.element.innerHTML = "";
if(val != null){
console.warn("Format Error - Formatter has returned a type of object, the only valid formatter object return is an instance of Node, the formatter returned:", val);
}
}
break;
case "undefined":
case "null":
this.element.innerHTML = "";
break;
default:
this.element.innerHTML = val;
}
};
Cell.prototype.cellRendered = function(){
if(this.table.modExists("format") && this.table.modules.format.cellRendered){
this.table.modules.format.cellRendered(this);
}
};
//generate tooltip text
Cell.prototype._generateTooltip = function(){
var tooltip = this.column.tooltip;
if(tooltip){
if(tooltip === true){
tooltip = this.value;
}else if(typeof(tooltip) == "function"){
tooltip = tooltip(this.getComponent());
if(tooltip === false){
tooltip = "";
}
}
if(typeof tooltip === "undefined"){
tooltip = "";
}
this.element.setAttribute("title", tooltip);
}else{
this.element.setAttribute("title", "");
}
};
//////////////////// Getters ////////////////////
Cell.prototype.getElement = function(){
return this.element;
};
Cell.prototype.getValue = function(){
return this.value;
};
Cell.prototype.getOldValue = function(){
return this.oldValue;
};
//////////////////// Actions ////////////////////
Cell.prototype.setValue = function(value, mutate){
var changed = this.setValueProcessData(value, mutate),
component;
if(changed){
if(this.table.options.history && this.table.modExists("history")){
this.table.modules.history.action("cellEdit", this, {oldValue:this.oldValue, newValue:this.value});
}
component = this.getComponent();
if(this.column.cellEvents.cellEdited){
this.column.cellEvents.cellEdited.call(this.table, component);
}
this.table.options.cellEdited.call(this.table, component);
this.table.options.dataEdited.call(this.table, this.table.rowManager.getData());
}
};
Cell.prototype.setValueProcessData = function(value, mutate){
var changed = false;
if(this.value != value){
changed = true;
if(mutate){
if(this.column.modules.mutate){
value = this.table.modules.mutator.transformCell(this, value);
}
}
}
this.setValueActual(value);
if(changed && this.table.modExists("columnCalcs")){
if(this.column.definition.topCalc || this.column.definition.bottomCalc){
if(this.table.options.groupBy && this.table.modExists("groupRows")){
if(this.table.options.columnCalcs == "table" || this.table.options.columnCalcs == "both"){
this.table.modules.columnCalcs.recalc(this.table.rowManager.activeRows);
}
if(this.table.options.columnCalcs != "table"){
this.table.modules.columnCalcs.recalcRowGroup(this.row);
}
}else{
this.table.modules.columnCalcs.recalc(this.table.rowManager.activeRows);
}
}
}
return changed;
};
Cell.prototype.setValueActual = function(value){
this.oldValue = this.value;
this.value = value;
if(this.table.options.reactiveData && this.table.modExists("reactiveData")){
this.table.modules.reactiveData.block();
}
this.column.setFieldValue(this.row.data, value);
if(this.table.options.reactiveData && this.table.modExists("reactiveData")){
this.table.modules.reactiveData.unblock();
}
this._generateContents();
this._generateTooltip();
//set resizable handles
if(this.table.options.resizableColumns && this.table.modExists("resizeColumns")){
this.table.modules.resizeColumns.initializeColumn("cell", this.column, this.element);
}
//handle frozen cells
if(this.table.modExists("frozenColumns")){
this.table.modules.frozenColumns.layoutElement(this.element, this.column);
}
};
Cell.prototype.setWidth = function(){
this.width = this.column.width;
this.element.style.width = this.column.widthStyled;
};
Cell.prototype.clearWidth = function(){
this.width = "";
this.element.style.width = "";
};
Cell.prototype.getWidth = function(){
return this.width || this.element.offsetWidth;
};
Cell.prototype.setMinWidth = function(){
this.minWidth = this.column.minWidth;
this.element.style.minWidth = this.column.minWidthStyled;
};
Cell.prototype.checkHeight = function(){
// var height = this.element.css("height");
this.row.reinitializeHeight();
};
Cell.prototype.clearHeight = function(){
this.element.style.height = "";
this.height = null;
};
Cell.prototype.setHeight = function(){
this.height = this.row.height;
this.element.style.height = this.row.heightStyled;
};
Cell.prototype.getHeight = function(){
return this.height || this.element.offsetHeight;
};
Cell.prototype.show = function(){
this.element.style.display = "";
};
Cell.prototype.hide = function(){
this.element.style.display = "none";
};
Cell.prototype.edit = function(force){
if(this.table.modExists("edit", true)){
return this.table.modules.edit.editCell(this, force);
}
};
Cell.prototype.cancelEdit = function(){
if(this.table.modExists("edit", true)){
var editing = this.table.modules.edit.getCurrentCell();
if(editing && editing._getSelf() === this){
this.table.modules.edit.cancelEdit();
}else{
console.warn("Cancel Editor Error - This cell is not currently being edited ");
}
}
};
Cell.prototype.delete = function(){
this.element.parentNode.removeChild(this.element);
this.element = false;
this.column.deleteCell(this);
this.row.deleteCell(this);
this.calcs = {};
};
//////////////// Navigation /////////////////
Cell.prototype.nav = function(){
var self = this,
nextCell = false,
index = this.row.getCellIndex(this);
return {
next:function(){
var nextCell = this.right(),
nextRow;
if(!nextCell){
nextRow = self.table.rowManager.nextDisplayRow(self.row, true);
if(nextRow){
nextCell = nextRow.findNextEditableCell(-1);
if(nextCell){
nextCell.edit();
return true;
}
}
}else{
return true;
}
return false;
},
prev:function(){
var nextCell = this.left(),
prevRow;
if(!nextCell){
prevRow = self.table.rowManager.prevDisplayRow(self.row, true);
if(prevRow){
nextCell = prevRow.findPrevEditableCell(prevRow.cells.length);
if(nextCell){
nextCell.edit();
return true;
}
}
}else{
return true;
}
return false;
},
left:function(){
nextCell = self.row.findPrevEditableCell(index);
if(nextCell){
nextCell.edit();
return true;
}else{
return false;
}
},
right:function(){
nextCell = self.row.findNextEditableCell(index);
if(nextCell){
nextCell.edit();
return true;
}else{
return false;
}
},
up:function(){
var nextRow = self.table.rowManager.prevDisplayRow(self.row, true);
if(nextRow){
nextRow.cells[index].edit();
}
},
down:function(){
var nextRow = self.table.rowManager.nextDisplayRow(self.row, true);
if(nextRow){
nextRow.cells[index].edit();
}
},
};
};
Cell.prototype.getIndex = function(){
this.row.getCellIndex(this);
};
//////////////// Object Generation /////////////////
Cell.prototype.getComponent = function(){
return new CellComponent(this);
};