UNPKG

tabulator-tables

Version:

Interactive table generation JavaScript library

908 lines (685 loc) 22.2 kB
//public row object var RowComponent = function (row){ this._row = row; }; RowComponent.prototype.getData = function(transform){ return this._row.getData(transform); }; RowComponent.prototype.getElement = function(){ return this._row.getElement(); }; RowComponent.prototype.getCells = function(){ var cells = []; this._row.getCells().forEach(function(cell){ cells.push(cell.getComponent()); }); return cells; }; RowComponent.prototype.getCell = function(column){ var cell = this._row.getCell(column); return cell ? cell.getComponent() : false; }; RowComponent.prototype.getIndex = function(){ return this._row.getData("data")[this._row.table.options.index]; }; RowComponent.prototype.getPosition = function(active){ return this._row.table.rowManager.getRowPosition(this._row, active); }; RowComponent.prototype.delete = function(){ return this._row.delete(); }; RowComponent.prototype.scrollTo = function(){ return this._row.table.rowManager.scrollToRow(this._row); }; RowComponent.prototype.pageTo = function(){ if(this._row.table.modExists("page", true)){ return this._row.table.modules.page.setPageToRow(this._row); } }; RowComponent.prototype.move = function(to, after){ this._row.moveToRow(to, after); }; RowComponent.prototype.update = function(data){ return this._row.updateData(data); }; RowComponent.prototype.normalizeHeight = function(){ this._row.normalizeHeight(true); }; RowComponent.prototype.select = function(){ this._row.table.modules.selectRow.selectRows(this._row); }; RowComponent.prototype.deselect = function(){ this._row.table.modules.selectRow.deselectRows(this._row); }; RowComponent.prototype.toggleSelect = function(){ this._row.table.modules.selectRow.toggleRow(this._row); }; RowComponent.prototype.isSelected = function(){ return this._row.table.modules.selectRow.isRowSelected(this._row); }; RowComponent.prototype._getSelf = function(){ return this._row; }; RowComponent.prototype.validate = function(){ return this._row.validate(); }; RowComponent.prototype.freeze = function(){ if(this._row.table.modExists("frozenRows", true)){ this._row.table.modules.frozenRows.freezeRow(this._row); } }; RowComponent.prototype.unfreeze = function(){ if(this._row.table.modExists("frozenRows", true)){ this._row.table.modules.frozenRows.unfreezeRow(this._row); } }; RowComponent.prototype.isFrozen = function(){ if(this._row.table.modExists("frozenRows", true)){ var index = this._row.table.modules.frozenRows.rows.indexOf(this._row); return index > -1; } return false; }; RowComponent.prototype.treeCollapse = function(){ if(this._row.table.modExists("dataTree", true)){ this._row.table.modules.dataTree.collapseRow(this._row); } }; RowComponent.prototype.treeExpand = function(){ if(this._row.table.modExists("dataTree", true)){ this._row.table.modules.dataTree.expandRow(this._row); } }; RowComponent.prototype.treeToggle = function(){ if(this._row.table.modExists("dataTree", true)){ this._row.table.modules.dataTree.toggleRow(this._row); } }; RowComponent.prototype.getTreeParent = function(){ if(this._row.table.modExists("dataTree", true)){ return this._row.table.modules.dataTree.getTreeParent(this._row); } return false; }; RowComponent.prototype.getTreeChildren = function(){ if(this._row.table.modExists("dataTree", true)){ return this._row.table.modules.dataTree.getTreeChildren(this._row, true); } return false; }; RowComponent.prototype.addTreeChild = function(data, pos, index){ if(this._row.table.modExists("dataTree", true)){ return this._row.table.modules.dataTree.addTreeChildRow(this._row, data, pos, index); } return false; }; RowComponent.prototype.reformat = function(){ return this._row.reinitialize(); }; RowComponent.prototype.getGroup = function(){ return this._row.getGroup().getComponent(); }; RowComponent.prototype.getTable = function(){ return this._row.table; }; RowComponent.prototype.getNextRow = function(){ var row = this._row.nextRow(); return row ? row.getComponent() : row; }; RowComponent.prototype.getPrevRow = function(){ var row = this._row.prevRow(); return row ? row.getComponent() : row; }; var Row = function(data, parent, type = "row"){ this.table = parent.table; this.parent = parent; this.data = {}; this.type = type; //type of element this.element = false; this.modules = {}; //hold module variables; this.cells = []; this.height = 0; //hold element height this.heightStyled = ""; //hold element height prestyled to improve render efficiency this.manualHeight = false; //user has manually set row height this.outerHeight = 0; //holde lements outer height this.initialized = false; //element has been rendered this.heightInitialized = false; //element has resized cells to fit this.component = null; this.created = false; this.setData(data); }; Row.prototype.create = function(){ if(!this.created){ this.created = true; this.generateElement(); } }; Row.prototype.createElement = function (){ var el = document.createElement("div"); el.classList.add("tabulator-row"); el.setAttribute("role", "row"); this.element = el; }; Row.prototype.getElement = function(){ this.create(); return this.element; }; Row.prototype.detachElement = function(){ if (this.element && this.element.parentNode){ this.element.parentNode.removeChild(this.element); } }; Row.prototype.generateElement = function(){ var self = this, dblTap, tapHold, tap; this.createElement(); //set row selection characteristics if(self.table.options.selectable !== false && self.table.modExists("selectRow")){ self.table.modules.selectRow.initializeRow(this); } //setup movable rows if(self.table.options.movableRows !== false && self.table.modExists("moveRow")){ self.table.modules.moveRow.initializeRow(this); } //setup data tree if(self.table.options.dataTree !== false && self.table.modExists("dataTree")){ self.table.modules.dataTree.initializeRow(this); } //setup column colapse container if(self.table.options.responsiveLayout === "collapse" && self.table.modExists("responsiveLayout")){ self.table.modules.responsiveLayout.initializeRow(this); } //set column menu if((self.table.options.rowContextMenu || self.table.options.rowClickMenu) && this.table.modExists("menu")){ self.table.modules.menu.initializeRow(this); } //handle row click events if (self.table.options.rowClick){ self.element.addEventListener("click", function(e){ self.table.options.rowClick(e, self.getComponent()); }); } if (self.table.options.rowDblClick){ self.element.addEventListener("dblclick", function(e){ self.table.options.rowDblClick(e, self.getComponent()); }); } if (self.table.options.rowContext){ self.element.addEventListener("contextmenu", function(e){ self.table.options.rowContext(e, self.getComponent()); }); } //handle mouse events if (self.table.options.rowMouseEnter){ self.element.addEventListener("mouseenter", function(e){ self.table.options.rowMouseEnter(e, self.getComponent()); }); } if (self.table.options.rowMouseLeave){ self.element.addEventListener("mouseleave", function(e){ self.table.options.rowMouseLeave(e, self.getComponent()); }); } if (self.table.options.rowMouseOver){ self.element.addEventListener("mouseover", function(e){ self.table.options.rowMouseOver(e, self.getComponent()); }); } if (self.table.options.rowMouseOut){ self.element.addEventListener("mouseout", function(e){ self.table.options.rowMouseOut(e, self.getComponent()); }); } if (self.table.options.rowMouseMove){ self.element.addEventListener("mousemove", function(e){ self.table.options.rowMouseMove(e, self.getComponent()); }); } if (self.table.options.rowTap){ tap = false; self.element.addEventListener("touchstart", function(e){ tap = true; }, {passive: true}); self.element.addEventListener("touchend", function(e){ if(tap){ self.table.options.rowTap(e, self.getComponent()); } tap = false; }); } if (self.table.options.rowDblTap){ dblTap = null; self.element.addEventListener("touchend", function(e){ if(dblTap){ clearTimeout(dblTap); dblTap = null; self.table.options.rowDblTap(e, self.getComponent()); }else{ dblTap = setTimeout(function(){ clearTimeout(dblTap); dblTap = null; }, 300); } }); } if (self.table.options.rowTapHold){ tapHold = null; self.element.addEventListener("touchstart", function(e){ clearTimeout(tapHold); tapHold = setTimeout(function(){ clearTimeout(tapHold); tapHold = null; tap = false; self.table.options.rowTapHold(e, self.getComponent()); }, 1000); }, {passive: true}); self.element.addEventListener("touchend", function(e){ clearTimeout(tapHold); tapHold = null; }); } }; Row.prototype.generateCells = function(){ this.cells = this.table.columnManager.generateCells(this); }; //functions to setup on first render Row.prototype.initialize = function(force){ this.create(); if(!this.initialized || force){ this.deleteCells(); while(this.element.firstChild) this.element.removeChild(this.element.firstChild); //handle frozen cells if(this.table.modExists("frozenColumns")){ this.table.modules.frozenColumns.layoutRow(this); } this.generateCells(); if(this.table.options.virtualDomHoz && this.table.vdomHoz.initialized){ this.table.vdomHoz.initializeRow(this); }else{ this.cells.forEach((cell) => { this.element.appendChild(cell.getElement()); cell.cellRendered(); }); } if(force){ this.normalizeHeight(); } //setup movable rows if(this.table.options.dataTree && this.table.modExists("dataTree")){ this.table.modules.dataTree.layoutRow(this); } //setup column colapse container if(this.table.options.responsiveLayout === "collapse" && this.table.modExists("responsiveLayout")){ this.table.modules.responsiveLayout.layoutRow(this); } if(this.table.options.rowFormatter){ this.table.options.rowFormatter(this.getComponent()); } //set resizable handles if(this.table.options.resizableRows && this.table.modExists("resizeRows")){ this.table.modules.resizeRows.initializeRow(this); } this.initialized = true; }else{ if(this.table.options.virtualDomHoz){ this.table.vdomHoz.reinitializeRow(this); } } }; Row.prototype.reinitializeHeight = function(){ this.heightInitialized = false; if(this.element && this.element.offsetParent !== null){ this.normalizeHeight(true); } }; Row.prototype.reinitialize = function(children){ this.initialized = false; this.heightInitialized = false; if(!this.manualHeight){ this.height = 0; this.heightStyled = ""; } if(this.element && this.element.offsetParent !== null){ this.initialize(true); } if(this.table.options.dataTree && this.table.modExists("dataTree", true)){ this.table.modules.dataTree.getTreeChildren(this, false, true).forEach(function(child){ child.reinitialize(true); }); } }; //get heights when doing bulk row style calcs in virtual DOM Row.prototype.calcHeight = function(force){ var maxHeight = 0, minHeight = this.table.options.resizableRows ? this.element.clientHeight : 0; this.cells.forEach(function(cell){ var height = cell.getHeight(); if(height > maxHeight){ maxHeight = height; } }); if(force){ this.height = Math.max(maxHeight, minHeight); }else{ this.height = this.manualHeight ? this.height : Math.max(maxHeight, minHeight); } this.heightStyled = this.height ? this.height + "px" : ""; this.outerHeight = this.element.offsetHeight; }; //set of cells Row.prototype.setCellHeight = function(){ this.cells.forEach(function(cell){ cell.setHeight(); }); this.heightInitialized = true; }; Row.prototype.clearCellHeight = function(){ this.cells.forEach(function(cell){ cell.clearHeight(); }); }; //normalize the height of elements in the row Row.prototype.normalizeHeight = function(force){ if(force){ this.clearCellHeight(); } this.calcHeight(force); this.setCellHeight(); }; // Row.prototype.setHeight = function(height){ // this.height = height; // this.setCellHeight(); // }; //set height of rows Row.prototype.setHeight = function(height, force){ if(this.height != height || force){ this.manualHeight = true; this.height = height; this.heightStyled = height ? height + "px" : ""; this.setCellHeight(); // this.outerHeight = this.element.outerHeight(); this.outerHeight = this.element.offsetHeight; } }; //return rows outer height Row.prototype.getHeight = function(){ return this.outerHeight; }; //return rows outer Width Row.prototype.getWidth = function(){ return this.element.offsetWidth; }; //////////////// Cell Management ///////////////// Row.prototype.deleteCell = function(cell){ var index = this.cells.indexOf(cell); if(index > -1){ this.cells.splice(index, 1); } }; //////////////// Data Management ///////////////// Row.prototype.setData = function(data){ if(this.table.modExists("mutator")){ data = this.table.modules.mutator.transformRow(data, "data"); } this.data = data; if(this.table.options.reactiveData && this.table.modExists("reactiveData", true)){ this.table.modules.reactiveData.watchRow(this); } }; //update the rows data Row.prototype.updateData = function(updatedData){ var visible = this.element && Tabulator.prototype.helpers.elVisible(this.element), tempData = {}, newRowData; return new Promise((resolve, reject) => { if(typeof updatedData === "string"){ updatedData = JSON.parse(updatedData); } if(this.table.options.reactiveData && this.table.modExists("reactiveData", true)){ this.table.modules.reactiveData.block(); } //mutate incomming data if needed if(this.table.modExists("mutator")){ tempData = Object.assign(tempData, this.data); tempData = Object.assign(tempData, updatedData); newRowData = this.table.modules.mutator.transformRow(tempData, "data", updatedData); }else{ newRowData = updatedData; } //set data for (var attrname in newRowData) { this.data[attrname] = newRowData[attrname]; } if(this.table.options.reactiveData && this.table.modExists("reactiveData", true)){ this.table.modules.reactiveData.unblock(); } //update affected cells only for (var attrname in updatedData) { let columns = this.table.columnManager.getColumnsByFieldRoot(attrname); columns.forEach((column) => { let cell = this.getCell(column.getField()); if(cell){ let value = column.getFieldValue(newRowData); if(cell.getValue() != value){ cell.setValueProcessData(value); if(visible){ cell.cellRendered(); } } } }); } if(this.table.options.groupUpdateOnCellEdit && this.table.options.groupBy && this.table.modExists("groupRows")) { this.table.modules.groupRows.reassignRowToGroup(this.row); } //Partial reinitialization if visible if(visible){ this.normalizeHeight(true); if(this.table.options.rowFormatter){ this.table.options.rowFormatter(this.getComponent()); } }else{ this.initialized = false; this.height = 0; this.heightStyled = ""; } if(this.table.options.dataTree !== false && this.table.modExists("dataTree") && this.table.modules.dataTree.redrawNeeded(updatedData)){ this.table.modules.dataTree.initializeRow(this); if(visible){ this.table.modules.dataTree.layoutRow(this); this.table.rowManager.refreshActiveData("tree", false, true); } } //this.reinitialize(); this.table.options.rowUpdated.call(this.table, this.getComponent()); if(this.table.options.dataChanged){ this.table.options.dataChanged.call(this.table, this.table.rowManager.getData()); } resolve(); }); }; Row.prototype.getData = function(transform){ if(transform){ if(this.table.modExists("accessor")){ return this.table.modules.accessor.transformRow(this, transform); } } return this.data; }; Row.prototype.getCell = function(column){ var match = false; column = this.table.columnManager.findColumn(column); match = this.cells.find(function(cell){ return cell.column === column; }); return match; }; Row.prototype.getCellIndex = function(findCell){ return this.cells.findIndex(function(cell){ return cell === findCell; }); }; Row.prototype.findNextEditableCell = function(index){ var nextCell = false; if(index < this.cells.length-1){ for(var i = index+1; i < this.cells.length; i++){ let cell = this.cells[i]; if(cell.column.modules.edit && Tabulator.prototype.helpers.elVisible(cell.getElement())){ let allowEdit = true; if(typeof cell.column.modules.edit.check == "function"){ allowEdit = cell.column.modules.edit.check(cell.getComponent()); } if(allowEdit){ nextCell = cell; break; } } } } return nextCell; }; Row.prototype.findPrevEditableCell = function(index){ var prevCell = false; if(index > 0){ for(var i = index-1; i >= 0; i--){ let cell = this.cells[i], allowEdit = true; if(cell.column.modules.edit && Tabulator.prototype.helpers.elVisible(cell.getElement())){ if(typeof cell.column.modules.edit.check == "function"){ allowEdit = cell.column.modules.edit.check(cell.getComponent()); } if(allowEdit){ prevCell = cell; break; } } } } return prevCell; }; Row.prototype.getCells = function(){ return this.cells; }; Row.prototype.nextRow = function(){ var row = this.table.rowManager.nextDisplayRow(this, true); return row || false; }; Row.prototype.prevRow = function(){ var row = this.table.rowManager.prevDisplayRow(this, true); return row || false; }; Row.prototype.moveToRow = function(to, before){ var toRow = this.table.rowManager.findRow(to); if(toRow){ this.table.rowManager.moveRowActual(this, toRow, !before); this.table.rowManager.refreshActiveData("display", false, true); }else{ console.warn("Move Error - No matching row found:", to); } }; Row.prototype.validate = function(){ var invalid = []; this.cells.forEach(function(cell){ if(!cell.validate()){ invalid.push(cell.getComponent()); } }); return invalid.length ? invalid : true; }; ///////////////////// Actions ///////////////////// Row.prototype.delete = function(){ return new Promise((resolve, reject) => { var index, rows; if(this.table.options.history && this.table.modExists("history")){ if(this.table.options.groupBy && this.table.modExists("groupRows")){ rows = this.getGroup().rows index = rows.indexOf(this); if(index){ index = rows[index-1]; } }else{ index = this.table.rowManager.getRowIndex(this); if(index){ index = this.table.rowManager.rows[index-1]; } } this.table.modules.history.action("rowDelete", this, {data:this.getData(), pos:!index, index:index}); } this.deleteActual(); resolve(); }); }; Row.prototype.deleteActual = function(blockRedraw){ var index = this.table.rowManager.getRowIndex(this); this.detatchModules(); // if(this.table.options.dataTree && this.table.modExists("dataTree")){ // this.table.modules.dataTree.collapseRow(this, true); // } //remove any reactive data watchers from row object if(this.table.options.reactiveData && this.table.modExists("reactiveData", true)){ // this.table.modules.reactiveData.unwatchRow(this); } //remove from group if(this.modules.group){ this.modules.group.removeRow(this); } this.table.rowManager.deleteRow(this, blockRedraw); this.deleteCells(); this.initialized = false; this.heightInitialized = false; this.element = false; if(this.table.options.dataTree && this.table.modExists("dataTree", true)){ this.table.modules.dataTree.rowDelete(this); } //recalc column calculations if present if(this.table.modExists("columnCalcs")){ if(this.table.options.groupBy && this.table.modExists("groupRows")){ this.table.modules.columnCalcs.recalcRowGroup(this); }else{ this.table.modules.columnCalcs.recalc(this.table.rowManager.activeRows); } } }; Row.prototype.detatchModules = function(){ //deselect row if it is selected if(this.table.modExists("selectRow")){ this.table.modules.selectRow._deselectRow(this, true); } //cancel edit if row is currently being edited if(this.table.modExists("edit")){ if(this.table.modules.edit.currentCell.row === this){ this.table.modules.edit.cancelEdit(); } } if(this.table.modExists("frozenRows")){ this.table.modules.frozenRows.detachRow(this); } }; Row.prototype.deleteCells = function(){ var cellCount = this.cells.length; for(let i = 0; i < cellCount; i++){ this.cells[0].delete(); } }; Row.prototype.wipe = function(){ this.detatchModules(); this.deleteCells(); if(this.element){ while(this.element.firstChild) this.element.removeChild(this.element.firstChild); if(this.element.parentNode){ this.element.parentNode.removeChild(this.element); } } this.element = false; this.modules = {}; }; Row.prototype.getGroup = function(){ return this.modules.group || false; }; //////////////// Object Generation ///////////////// Row.prototype.getComponent = function(){ if(!this.component){ this.component = new RowComponent(this); } return this.component; };