1 var RowManager =
function(table){
4 this.element = this.createHolderElement();
5 this.tableElement = this.createTableElement();
6 this.columnManager = null;
9 this.firstRender =
false;
10 this.renderMode =
"classic";
14 this.activeRowsCount = 0;
16 this.displayRows = [];
17 this.displayRowsCount = 0;
22 this.vDomRowHeight = 20;
27 this.vDomScrollPosTop = 0;
28 this.vDomScrollPosBottom = 0;
31 this.vDomBottomPad = 0;
33 this.vDomMaxRenderChain = 90;
35 this.vDomWindowBuffer = 0;
37 this.vDomWindowMinTotalRows = 20;
38 this.vDomWindowMinMarginRows = 5;
40 this.vDomTopNewRows = [];
41 this.vDomBottomNewRows = [];
43 this.rowNumColumn =
false;
45 this.redrawBlock =
false;
46 this.redrawBlockRestoreConfig =
false;
47 this.redrawBlockRederInPosition =
false;
52 RowManager.prototype.createHolderElement =
function (){
53 var el = document.createElement(
"div");
55 el.classList.add(
"tabulator-tableHolder");
56 el.setAttribute(
"tabindex", 0);
61 RowManager.prototype.createTableElement =
function (){
62 var el = document.createElement(
"div");
64 el.classList.add(
"tabulator-table");
70 RowManager.prototype.getElement =
function(){
75 RowManager.prototype.getTableElement =
function(){
76 return this.tableElement;
80 RowManager.prototype.getRowPosition =
function(row, active){
82 return this.activeRows.indexOf(row);
84 return this.rows.indexOf(row);
90 RowManager.prototype.setColumnManager =
function(manager){
91 this.columnManager = manager;
94 RowManager.prototype.initialize =
function(){
100 self.element.appendChild(
self.tableElement);
102 self.firstRender =
true;
105 self.element.addEventListener(
"scroll",
function(){
106 var left =
self.element.scrollLeft;
109 if(
self.scrollLeft != left){
110 self.columnManager.scrollHorizontal(left);
112 if(
self.table.options.groupBy){
113 self.table.modules.groupRows.scrollHeaders(left);
116 if(
self.table.modExists(
"columnCalcs")){
117 self.table.modules.columnCalcs.scrollHorizontal(left);
120 self.table.options.scrollHorizontal(left);
123 self.scrollLeft = left;
127 if(this.renderMode ===
"virtual"){
129 self.element.addEventListener(
"scroll",
function(){
130 var top =
self.element.scrollTop;
131 var dir =
self.scrollTop > top;
134 if(
self.scrollTop != top){
135 self.scrollTop = top;
136 self.scrollVertical(dir);
138 if(
self.table.options.ajaxProgressiveLoad ==
"scroll"){
139 self.table.modules.ajax.nextPage(
self.element.scrollHeight -
self.element.clientHeight - top);
142 self.table.options.scrollVertical(top);
144 self.scrollTop = top;
154 RowManager.prototype.findRow =
function(subject){
157 if(typeof subject ==
"object"){
159 if(subject instanceof Row){
162 }
else if(subject instanceof RowComponent){
164 return subject._getSelf() ||
false;
165 }
else if(typeof HTMLElement !==
"undefined" && subject instanceof HTMLElement){
167 let match =
self.rows.find(
function(row){
168 return row.element === subject;
171 return match ||
false;
174 }
else if(typeof subject ==
"undefined" || subject === null){
178 let match =
self.rows.find(
function(row){
179 return row.data[
self.table.options.index] == subject;
182 return match ||
false;
191 RowManager.prototype.getRowFromDataObject =
function(data){
192 var match = this.rows.find(
function(row){
193 return row.data === data;
196 return match ||
false;
199 RowManager.prototype.getRowFromPosition =
function(position, active){
201 return this.activeRows[position];
203 return this.rows[position];
207 RowManager.prototype.scrollToRow =
function(row, position, ifVisible){
208 var rowIndex = this.getDisplayRows().indexOf(row),
209 rowEl = row.getElement(),
213 return new Promise((resolve, reject) => {
216 if(typeof position ===
"undefined"){
217 position = this.table.options.scrollToRowPosition;
220 if(typeof ifVisible ===
"undefined"){
221 ifVisible = this.table.options.scrollToRowIfVisible;
225 if(position ===
"nearest"){
226 switch(this.renderMode){
228 rowTop = Tabulator.prototype.helpers.elOffset(rowEl).top;
229 position = Math.abs(this.element.scrollTop - rowTop) > Math.abs(this.element.scrollTop +
this.element.clientHeight - rowTop) ?
"bottom" :
"top";
232 position = Math.abs(this.vDomTop - rowIndex) > Math.abs(this.vDomBottom - rowIndex) ?
"bottom" :
"top";
239 if(Tabulator.prototype.helpers.elVisible(rowEl)){
240 offset = Tabulator.prototype.helpers.elOffset(rowEl).top - Tabulator.prototype.helpers.elOffset(this.element).top;
242 if(offset > 0 && offset < this.element.clientHeight - rowEl.offsetHeight){
249 switch(this.renderMode){
251 this.element.scrollTop = Tabulator.prototype.helpers.elOffset(rowEl).top - Tabulator.prototype.helpers.elOffset(this.element).top + this.element.scrollTop;
254 this._virtualRenderFill(rowIndex,
true);
263 if(this.element.scrollHeight -
this.element.scrollTop ==
this.element.clientHeight){
264 this.element.scrollTop = this.element.scrollTop + (rowEl.offsetTop - this.element.scrollTop) - ((this.element.scrollHeight - rowEl.offsetTop) / 2);
266 this.element.scrollTop = this.element.scrollTop - (this.element.clientHeight / 2);
273 if(this.element.scrollHeight -
this.element.scrollTop ==
this.element.clientHeight){
274 this.element.scrollTop = this.element.scrollTop - (this.element.scrollHeight - rowEl.offsetTop) + rowEl.offsetHeight;
276 this.element.scrollTop = this.element.scrollTop - this.element.clientHeight + rowEl.offsetHeight;
285 console.warn(
"Scroll Error - Row not visible");
286 reject(
"Scroll Error - Row not visible");
294 RowManager.prototype.setData =
function(data, renderInPosition){
297 return new Promise((resolve, reject)=>{
298 if(renderInPosition && this.getDisplayRows().length){
299 if(
self.table.options.pagination){
300 self._setDataActual(data,
true);
302 this.reRenderInPosition(
function(){
303 self._setDataActual(data);
307 if(this.table.options.autoColumns){
308 this.table.columnManager.generateColumnsFromRowData(data);
311 this._setDataActual(data);
318 RowManager.prototype._setDataActual =
function(data, renderInPosition){
321 self.table.options.dataLoading.call(this.table, data);
323 this._wipeElements();
325 if(this.table.options.history &&
this.table.modExists(
"history")){
326 this.table.modules.history.clear();
329 if(Array.isArray(data)){
331 if(this.table.modExists(
"selectRow")){
332 this.table.modules.selectRow.clearSelectionData();
335 if(this.table.options.reactiveData &&
this.table.modExists(
"reactiveData",
true)){
336 this.table.modules.reactiveData.watchData(data);
339 data.forEach(
function(def, i){
340 if(def && typeof def ===
"object"){
341 var row =
new Row(def,
self);
344 console.warn(
"Data Loading Warning - Invalid row data detected and ignored, expecting object but received:", def);
348 self.table.options.dataLoaded.call(this.table, data);
350 self.refreshActiveData(
false,
false, renderInPosition);
352 console.error(
"Data Loading Error - Unable to process data due to invalid data type \nExpecting: array \nReceived: ", typeof data,
"\nData: ", data);
356 RowManager.prototype._wipeElements =
function(){
357 this.rows.forEach(
function(row){
361 if(this.table.options.groupBy &&
this.table.modExists(
"groupRows")){
362 this.table.modules.groupRows.wipe();
368 RowManager.prototype.deleteRow =
function(row, blockRedraw){
369 var allIndex = this.rows.indexOf(row),
370 activeIndex = this.activeRows.indexOf(row);
372 if(activeIndex > -1){
373 this.activeRows.splice(activeIndex, 1);
377 this.rows.splice(allIndex, 1);
380 this.setActiveRows(this.activeRows);
382 this.displayRowIterator(
function(rows){
383 var displayIndex = rows.indexOf(row);
385 if(displayIndex > -1){
386 rows.splice(displayIndex, 1);
391 this.reRenderInPosition();
394 this.table.options.rowDeleted.call(this.table, row.getComponent());
396 this.table.options.dataEdited.call(this.table, this.getData());
398 if(this.table.options.groupBy &&
this.table.modExists(
"groupRows")){
399 this.table.modules.groupRows.updateGroupRows(
true);
400 }
else if(this.table.options.pagination &&
this.table.modExists(
"page")){
401 this.refreshActiveData(
false,
false,
true);
403 if(this.table.options.pagination &&
this.table.modExists(
"page")){
404 this.refreshActiveData(
"page");
410 RowManager.prototype.addRow =
function(data, pos, index, blockRedraw){
412 var row = this.addRowActual(data, pos, index, blockRedraw);
414 if(this.table.options.history &&
this.table.modExists(
"history")){
415 this.table.modules.history.action(
"rowAdd", row, {data:data, pos:pos, index:index});
422 RowManager.prototype.addRows =
function(data, pos, index){
427 return new Promise((resolve, reject) => {
428 pos = this.findAddRowPos(pos);
430 if(!Array.isArray(data)){
434 length = data.length - 1;
436 if((typeof index ==
"undefined" && pos) || (typeof index !==
"undefined" && !pos)){
440 data.forEach(
function(item, i){
441 var row =
self.addRow(item, pos, index,
true);
445 if(this.table.options.groupBy &&
this.table.modExists(
"groupRows")){
446 this.table.modules.groupRows.updateGroupRows(
true);
447 }
else if(this.table.options.pagination &&
this.table.modExists(
"page")){
448 this.refreshActiveData(
false,
false,
true);
450 this.reRenderInPosition();
454 if(this.table.modExists(
"columnCalcs")){
455 this.table.modules.columnCalcs.recalc(this.table.rowManager.activeRows);
462 RowManager.prototype.findAddRowPos =
function(pos){
463 if(typeof pos ===
"undefined"){
464 pos = this.table.options.addRowPos;
471 if(pos ===
"bottom"){
479 RowManager.prototype.addRowActual =
function(data, pos, index, blockRedraw){
480 var row = data instanceof Row ? data :
new Row(data || {},
this),
481 top = this.findAddRowPos(pos),
484 if(!index && this.table.options.pagination &&
this.table.options.paginationAddRow ==
"page"){
485 dispRows = this.getDisplayRows();
491 if(this.activeRows.length){
492 index = this.activeRows[this.activeRows.length-1];
498 index = dispRows[dispRows.length - 1];
499 top = dispRows.length < this.table.modules.page.getPageSize() ?
false :
true;
505 index = this.findRow(index);
508 if(this.table.options.groupBy &&
this.table.modExists(
"groupRows")){
509 this.table.modules.groupRows.assignRowToGroup(row);
511 var groupRows = row.getGroup().rows;
513 if(groupRows.length > 1){
515 if(!index || (index && groupRows.indexOf(index) == -1)){
517 if(groupRows[0] !== row){
518 index = groupRows[0];
519 this._moveRowInArray(row.getGroup().rows, row, index, !top);
522 if(groupRows[groupRows.length -1] !== row){
523 index = groupRows[groupRows.length -1];
524 this._moveRowInArray(row.getGroup().rows, row, index, !top);
528 this._moveRowInArray(row.getGroup().rows, row, index, !top);
534 let allIndex = this.rows.indexOf(index),
535 activeIndex = this.activeRows.indexOf(index);
537 this.displayRowIterator(
function(rows){
538 var displayIndex = rows.indexOf(index);
540 if(displayIndex > -1){
541 rows.splice((top ? displayIndex : displayIndex + 1), 0, row);
545 if(activeIndex > -1){
546 this.activeRows.splice((top ? activeIndex : activeIndex + 1), 0, row);
550 this.rows.splice((top ? allIndex : allIndex + 1), 0, row);
557 this.displayRowIterator(
function(rows){
561 this.activeRows.unshift(row);
562 this.rows.unshift(row);
564 this.displayRowIterator(
function(rows){
568 this.activeRows.push(row);
573 this.setActiveRows(this.activeRows);
575 this.table.options.rowAdded.call(this.table, row.getComponent());
577 this.table.options.dataEdited.call(this.table, this.getData());
580 this.reRenderInPosition();
586 RowManager.prototype.moveRow =
function(from, to, after){
587 if(this.table.options.history &&
this.table.modExists(
"history")){
588 this.table.modules.history.action(
"rowMove", from, {pos:this.getRowPosition(from), to:to, after:after});
591 this.moveRowActual(from, to, after);
593 this.table.options.rowMoved.call(this.table, from.getComponent());
597 RowManager.prototype.moveRowActual =
function(from, to, after){
599 this._moveRowInArray(this.rows, from, to, after);
600 this._moveRowInArray(this.activeRows, from, to, after);
602 this.displayRowIterator(
function(rows){
603 self._moveRowInArray(rows, from, to, after);
606 if(this.table.options.groupBy &&
this.table.modExists(
"groupRows")){
607 var toGroup = to.getGroup();
608 var fromGroup = from.getGroup();
610 if(toGroup === fromGroup){
611 this._moveRowInArray(toGroup.rows, from, to, after);
614 fromGroup.removeRow(from);
617 toGroup.insertRow(from, to, after);
623 RowManager.prototype._moveRowInArray =
function(rows, from, to, after){
624 var fromIndex, toIndex, start, end;
628 fromIndex = rows.indexOf(from);
630 if (fromIndex > -1) {
632 rows.splice(fromIndex, 1);
634 toIndex = rows.indexOf(to);
639 rows.splice(toIndex+1, 0, from);
641 rows.splice(toIndex, 0, from);
645 rows.splice(fromIndex, 0, from);
650 if(rows === this.getDisplayRows()){
652 start = fromIndex < toIndex ? fromIndex : toIndex;
653 end = toIndex > fromIndex ? toIndex : fromIndex +1;
655 for(let i = start; i <= end; i++){
657 this.styleRow(rows[i], i);
664 RowManager.prototype.clearData =
function(){
668 RowManager.prototype.getRowIndex =
function(row){
669 return this.findRowIndex(row, this.rows);
673 RowManager.prototype.getDisplayRowIndex =
function(row){
674 var index = this.getDisplayRows().indexOf(row);
675 return index > -1 ? index :
false;
678 RowManager.prototype.nextDisplayRow =
function(row, rowOnly){
679 var index = this.getDisplayRowIndex(row),
683 if(index !==
false && index < this.displayRowsCount -1){
684 nextRow = this.getDisplayRows()[index+1];
687 if(nextRow && (!(nextRow instanceof Row) || nextRow.type !=
"row")){
688 return this.nextDisplayRow(nextRow, rowOnly);
694 RowManager.prototype.prevDisplayRow =
function(row, rowOnly){
695 var index = this.getDisplayRowIndex(row),
699 prevRow = this.getDisplayRows()[index-1];
702 if(prevRow && (!(prevRow instanceof Row) || prevRow.type !=
"row")){
703 return this.prevDisplayRow(prevRow, rowOnly);
709 RowManager.prototype.findRowIndex =
function(row, list){
712 row = this.findRow(row);
715 rowIndex = list.indexOf(row);
726 RowManager.prototype.getData =
function(active, transform){
728 rows = this.getRows(active);
730 rows.forEach(
function(row){
731 output.push(row.getData(transform ||
"data"));
737 RowManager.prototype.getComponents =
function(active){
739 rows = this.getRows(active);
741 rows.forEach(
function(row){
742 output.push(row.getComponent());
748 RowManager.prototype.getDataCount =
function(active){
749 var rows = this.getRows(active);
754 RowManager.prototype._genRemoteRequest =
function(){
757 options = table.options,
760 if(table.modExists(
"page")){
762 if(options.ajaxSorting){
763 let sorters =
self.table.modules.sort.getSort();
765 sorters.forEach(
function(item){
769 params[
self.table.modules.page.paginationDataSentNames.sorters] = sorters;
773 if(options.ajaxFiltering){
774 let filters =
self.table.modules.filter.getFilters(
true,
true);
776 params[
self.table.modules.page.paginationDataSentNames.filters] = filters;
780 self.table.modules.ajax.setParams(params,
true);
783 table.modules.ajax.sendRequest()
792 RowManager.prototype.filterRefresh =
function(){
793 var table = this.table,
794 options = table.options,
795 left = this.scrollLeft;
798 if(options.ajaxFiltering){
799 if(options.pagination ==
"remote" && table.modExists(
"page")){
800 table.modules.page.reset(
true);
801 table.modules.page.setPage(1).then(()=>{}).
catch(()=>{});
802 }
else if(options.ajaxProgressiveLoad){
803 table.modules.ajax.loadData().then(()=>{}).
catch(()=>{});
806 this._genRemoteRequest();
809 this.refreshActiveData(
"filter");
812 this.scrollHorizontal(left);
816 RowManager.prototype.sorterRefresh =
function(loadOrignalData){
817 var table = this.table,
818 options = this.table.options,
819 left = this.scrollLeft;
821 if(options.ajaxSorting){
822 if((options.pagination ==
"remote" || options.progressiveLoad) && table.modExists(
"page")){
823 table.modules.page.reset(
true);
824 table.modules.page.setPage(1).then(()=>{}).
catch(()=>{});
825 }
else if(options.ajaxProgressiveLoad){
826 table.modules.ajax.loadData().then(()=>{}).
catch(()=>{});
829 this._genRemoteRequest();
832 this.refreshActiveData(loadOrignalData ?
"filter" :
"sort");
835 this.scrollHorizontal(left);
838 RowManager.prototype.scrollHorizontal =
function(left){
839 this.scrollLeft = left;
840 this.element.scrollLeft = left;
842 if(this.table.options.groupBy){
843 this.table.modules.groupRows.scrollHeaders(left);
846 if(this.table.modExists(
"columnCalcs")){
847 this.table.modules.columnCalcs.scrollHorizontal(left);
852 RowManager.prototype.refreshActiveData =
function(stage, skipStage, renderInPosition){
855 cascadeOrder = [
"all",
"filter",
"sort",
"display",
"freeze",
"group",
"tree",
"page"],
858 if(this.redrawBlock){
860 if(!this.redrawBlockRestoreConfig || (cascadeOrder.indexOf(stage) < cascadeOrder.indexOf(this.redrawBlockRestoreConfig.stage))){
861 this.redrawBlockRestoreConfig = {
863 skipStage: skipStage,
864 renderInPosition: renderInPosition,
871 if(
self.table.modExists(
"edit")){
872 self.table.modules.edit.cancelEdit();
879 if(table.options.selectable && !table.options.selectablePersistence && table.modExists(
"selectRow")){
880 table.modules.selectRow.deselectRows();
889 if(table.modExists(
"filter")){
890 self.setActiveRows(table.modules.filter.filter(
self.rows));
892 self.setActiveRows(
self.rows.slice(0));
900 if(table.modExists(
"sort")){
901 table.modules.sort.sort(this.activeRows);
908 if(this.rowNumColumn){
909 this.activeRows.forEach((row) => {
910 var cell = row.getCell(this.rowNumColumn);
913 cell._generateContents();
920 this.resetDisplayRows();
924 if(this.table.modExists(
"frozenRows")){
925 if(table.modules.frozenRows.isFrozen()){
926 if(!table.modules.frozenRows.getDisplayIndex()){
927 table.modules.frozenRows.setDisplayIndex(this.getNextDisplayIndex());
930 displayIndex = table.modules.frozenRows.getDisplayIndex();
932 displayIndex =
self.setDisplayRows(table.modules.frozenRows.getRows(
this.getDisplayRows(displayIndex - 1)), displayIndex);
934 if(displayIndex !==
true){
935 table.modules.frozenRows.setDisplayIndex(displayIndex);
945 if(table.options.groupBy && table.modExists(
"groupRows")){
947 if(!table.modules.groupRows.getDisplayIndex()){
948 table.modules.groupRows.setDisplayIndex(this.getNextDisplayIndex());
951 displayIndex = table.modules.groupRows.getDisplayIndex();
953 displayIndex =
self.setDisplayRows(table.modules.groupRows.getRows(
this.getDisplayRows(displayIndex - 1)), displayIndex);
955 if(displayIndex !==
true){
956 table.modules.groupRows.setDisplayIndex(displayIndex);
968 if(table.options.dataTree && table.modExists(
"dataTree")){
969 if(!table.modules.dataTree.getDisplayIndex()){
970 table.modules.dataTree.setDisplayIndex(this.getNextDisplayIndex());
973 displayIndex = table.modules.dataTree.getDisplayIndex();
975 displayIndex =
self.setDisplayRows(table.modules.dataTree.getRows(
this.getDisplayRows(displayIndex - 1)), displayIndex);
977 if(displayIndex !==
true){
978 table.modules.dataTree.setDisplayIndex(displayIndex);
985 if(table.options.pagination && table.modExists(
"page") && !renderInPosition){
986 if(table.modules.page.getMode() ==
"local"){
987 table.modules.page.reset();
993 if(table.options.pagination && table.modExists(
"page")){
995 if(!table.modules.page.getDisplayIndex()){
996 table.modules.page.setDisplayIndex(this.getNextDisplayIndex());
999 displayIndex = table.modules.page.getDisplayIndex();
1001 if(table.modules.page.getMode() ==
"local"){
1002 table.modules.page.setMaxRows(this.getDisplayRows(displayIndex - 1).length);
1006 displayIndex =
self.setDisplayRows(table.modules.page.getRows(
this.getDisplayRows(displayIndex - 1)), displayIndex);
1008 if(displayIndex !==
true){
1009 table.modules.page.setDisplayIndex(displayIndex);
1018 if(Tabulator.prototype.helpers.elVisible(
self.element)){
1019 if(renderInPosition){
1020 self.reRenderInPosition();
1023 if(table.options.layoutColumnsOnNewData){
1024 self.table.columnManager.redraw(
true);
1029 if(table.modExists(
"columnCalcs")){
1030 table.modules.columnCalcs.recalc(this.activeRows);
1035 RowManager.prototype.setActiveRows =
function(activeRows){
1036 this.activeRows = activeRows;
1037 this.activeRowsCount = this.activeRows.length;
1041 RowManager.prototype.resetDisplayRows =
function(){
1042 this.displayRows = [];
1044 this.displayRows.push(this.activeRows.slice(0));
1046 this.displayRowsCount = this.displayRows[0].length;
1048 if(this.table.modExists(
"frozenRows")){
1049 this.table.modules.frozenRows.setDisplayIndex(0);
1052 if(this.table.options.groupBy &&
this.table.modExists(
"groupRows")){
1053 this.table.modules.groupRows.setDisplayIndex(0);
1056 if(this.table.options.pagination &&
this.table.modExists(
"page")){
1057 this.table.modules.page.setDisplayIndex(0);
1062 RowManager.prototype.getNextDisplayIndex =
function(){
1063 return this.displayRows.length;
1067 RowManager.prototype.setDisplayRows =
function(displayRows, index){
1071 if(index && typeof this.displayRows[index] !=
"undefined"){
1072 this.displayRows[index] = displayRows;
1075 this.displayRows.push(displayRows)
1076 output = index = this.displayRows.length -1;
1079 if(index == this.displayRows.length -1){
1080 this.displayRowsCount = this.displayRows[this.displayRows.length -1].length;
1086 RowManager.prototype.getDisplayRows =
function(index){
1087 if(typeof index ==
"undefined"){
1088 return this.displayRows.length ? this.displayRows[this.displayRows.length -1] : [];
1090 return this.displayRows[index] || [];
1096 RowManager.prototype.getVisibleRows =
function(viewable){
1097 var topEdge = this.element.scrollTop,
1098 bottomEdge = this.element.clientHeight + topEdge,
1102 rows = this.getDisplayRows();
1106 this.getDisplayRows();
1107 for(var i = this.vDomTop; i <= this.vDomBottom; i++){
1110 if((topEdge - rows[i].getElement().offsetTop) >= 0){
1115 if(bottomEdge - rows[i].getElement().offsetTop >= 0){
1122 if(bottomEdge - rows[i].getElement().offsetTop >= 0){
1131 topRow = this.vDomTop;
1132 bottomRow = this.vDomBottom;
1135 return rows.slice(topRow, bottomRow + 1);
1140 RowManager.prototype.displayRowIterator =
function(callback){
1141 this.displayRows.forEach(callback);
1143 this.displayRowsCount = this.displayRows[this.displayRows.length -1].length;
1147 RowManager.prototype.getRows =
function(active){
1152 rows = this.activeRows;
1156 rows = this.getVisibleRows(
true);
1169 RowManager.prototype.reRenderInPosition =
function(callback){
1170 if(this.getRenderMode() ==
"virtual"){
1172 if(this.redrawBlock){
1176 this.redrawBlockRederInPosition =
true;
1179 var scrollTop = this.element.scrollTop;
1181 var topOffset =
false;
1183 var left = this.scrollLeft;
1185 var rows = this.getDisplayRows();
1187 for(var i = this.vDomTop; i <= this.vDomBottom; i++){
1190 var diff = scrollTop - rows[i].getElement().offsetTop;
1192 if(topOffset ===
false || Math.abs(diff) < topOffset){
1205 this._virtualRenderFill((topRow ===
false ? this.displayRowsCount - 1 : topRow),
true, topOffset || 0);
1207 this.scrollHorizontal(left);
1218 RowManager.prototype.setRenderMode =
function(){
1219 if((this.table.element.clientHeight ||
this.table.options.height) && this.table.options.virtualDom){
1220 this.renderMode =
"virtual";
1222 this.renderMode =
"classic";
1227 RowManager.prototype.getRenderMode =
function(){
1228 return this.renderMode;
1231 RowManager.prototype.renderTable =
function(){
1234 self.table.options.renderStarted.call(this.table);
1236 self.element.scrollTop = 0;
1238 switch(
self.renderMode){
1240 self._simpleRender();
1244 self._virtualRenderFill();
1248 if(
self.firstRender){
1249 if(
self.displayRowsCount){
1250 self.firstRender =
false;
1251 self.table.modules.layout.layout();
1253 self.renderEmptyScroll();
1257 if(
self.table.modExists(
"frozenColumns")){
1258 self.table.modules.frozenColumns.layout();
1262 if(!
self.displayRowsCount){
1263 if(
self.table.options.placeholder){
1265 if(this.renderMode){
1266 self.table.options.placeholder.setAttribute(
"tabulator-render-mode", this.renderMode);
1269 self.getElement().appendChild(
self.table.options.placeholder);
1273 self.table.options.renderComplete.call(this.table);
1277 RowManager.prototype._simpleRender =
function(){
1278 this._clearVirtualDom();
1280 if(this.displayRowsCount){
1281 this.checkClassicModeGroupHeaderWidth();
1283 this.renderEmptyScroll();
1287 RowManager.prototype.checkClassicModeGroupHeaderWidth =
function(){
1289 element = this.tableElement,
1290 onlyGroupHeaders =
true;
1292 self.getDisplayRows().forEach(
function(row, index){
1293 self.styleRow(row, index);
1294 element.appendChild(row.getElement());
1295 row.initialize(
true);
1297 if(row.type !==
"group"){
1298 onlyGroupHeaders =
false;
1302 if(onlyGroupHeaders){
1303 element.style.minWidth =
self.table.columnManager.getWidth() +
"px";
1305 element.style.minWidth =
"";
1310 RowManager.prototype.renderEmptyScroll =
function(){
1311 this.tableElement.style.minWidth = this.table.columnManager.getWidth() +
"px";
1312 this.tableElement.style.minHeight =
"1px";
1313 this.tableElement.style.visibility =
"hidden";
1316 RowManager.prototype._clearVirtualDom =
function(){
1317 var element = this.tableElement;
1319 if(this.table.options.placeholder &&
this.table.options.placeholder.parentNode){
1320 this.table.options.placeholder.parentNode.removeChild(this.table.options.placeholder);
1324 while(element.firstChild) element.removeChild(element.firstChild);
1326 element.style.paddingTop =
"";
1327 element.style.paddingBottom =
"";
1328 element.style.minWidth =
"";
1329 element.style.minHeight =
"";
1330 element.style.visibility =
"";
1333 this.scrollLeft = 0;
1335 this.vDomBottom = 0;
1336 this.vDomTopPad = 0;
1337 this.vDomBottomPad = 0;
1340 RowManager.prototype.styleRow =
function(row, index){
1341 var rowEl = row.getElement();
1344 rowEl.classList.add(
"tabulator-row-even");
1345 rowEl.classList.remove(
"tabulator-row-odd");
1347 rowEl.classList.add(
"tabulator-row-odd");
1348 rowEl.classList.remove(
"tabulator-row-even");
1353 RowManager.prototype._virtualRenderFill =
function(position, forceMove, offset){
1355 element =
self.tableElement,
1356 holder =
self.element,
1361 onlyGroupHeaders =
true,
1362 rows =
self.getDisplayRows();
1364 position = position || 0;
1366 offset = offset || 0;
1369 self._clearVirtualDom();
1371 while(element.firstChild) element.removeChild(element.firstChild);
1374 let heightOccupied = (
self.displayRowsCount - position + 1) *
self.vDomRowHeight;
1376 if(heightOccupied <
self.height){
1377 position -= Math.ceil((
self.height - heightOccupied ) /
self.vDomRowHeight);
1385 topPad = Math.min(Math.max(Math.floor(
self.vDomWindowBuffer /
self.vDomRowHeight),
self.vDomWindowMinMarginRows), position);
1389 if(
self.displayRowsCount && Tabulator.prototype.helpers.elVisible(
self.element)){
1391 self.vDomTop = position;
1393 self.vDomBottom = position -1;
1395 while ((rowsHeight <=
self.height +
self.vDomWindowBuffer || i <
self.vDomWindowMinTotalRows) &&
self.vDomBottom <
self.displayRowsCount -1){
1396 var index =
self.vDomBottom + 1,
1400 self.styleRow(row, index);
1402 element.appendChild(row.getElement());
1403 if(!row.initialized){
1404 row.initialize(
true);
1406 if(!row.heightInitialized){
1407 row.normalizeHeight(
true);
1411 rowHeight = row.getHeight();
1414 topPadHeight += rowHeight;
1416 rowsHeight += rowHeight;
1420 if(rowHeight > this.vDomWindowBuffer){
1421 this.vDomWindowBuffer = rowHeight * 2;
1424 if(row.type !==
"group"){
1425 onlyGroupHeaders =
false;
1433 this.vDomTopPad = 0;
1435 self.vDomRowHeight = Math.floor((rowsHeight + topPadHeight) / i);
1436 self.vDomBottomPad =
self.vDomRowHeight * (
self.displayRowsCount -
self.vDomBottom -1);
1438 self.vDomScrollHeight = topPadHeight + rowsHeight +
self.vDomBottomPad -
self.height;
1440 self.vDomTopPad = !forceMove ?
self.scrollTop - topPadHeight : (
self.vDomRowHeight * this.vDomTop) + offset;
1441 self.vDomBottomPad =
self.vDomBottom ==
self.displayRowsCount-1 ? 0 : Math.max(
self.vDomScrollHeight -
self.vDomTopPad - rowsHeight - topPadHeight, 0);
1444 element.style.paddingTop =
self.vDomTopPad +
"px";
1445 element.style.paddingBottom =
self.vDomBottomPad +
"px";
1448 this.scrollTop =
self.vDomTopPad + (topPadHeight) + offset - (this.element.scrollWidth >
this.element.clientWidth ?
this.element.offsetHeight -
this.element.clientHeight : 0);
1451 this.scrollTop = Math.min(this.scrollTop, this.element.scrollHeight -
this.height);
1454 if(this.element.scrollWidth >
this.element.offsetWidth && forceMove){
1455 this.scrollTop += this.element.offsetHeight - this.element.clientHeight;
1458 this.vDomScrollPosTop = this.scrollTop;
1459 this.vDomScrollPosBottom = this.scrollTop;
1461 holder.scrollTop = this.scrollTop;
1463 element.style.minWidth = onlyGroupHeaders ?
self.table.columnManager.getWidth() +
"px" :
"";
1465 if(
self.table.options.groupBy){
1466 if(
self.table.modules.layout.getMode() !=
"fitDataFill" &&
self.displayRowsCount ==
self.table.modules.groupRows.countGroups()){
1467 self.tableElement.style.minWidth =
self.table.columnManager.getWidth();
1472 this.renderEmptyScroll();
1477 RowManager.prototype.scrollVertical =
function(dir){
1478 var topDiff = this.scrollTop - this.vDomScrollPosTop;
1479 var bottomDiff = this.scrollTop - this.vDomScrollPosBottom;
1480 var margin = this.vDomWindowBuffer * 2;
1482 if(-topDiff > margin || bottomDiff > margin){
1484 var left = this.scrollLeft;
1485 this._virtualRenderFill(Math.floor((
this.element.scrollTop /
this.element.scrollHeight) *
this.displayRowsCount));
1486 this.scrollHorizontal(left);
1492 this._addTopRow(-topDiff);
1498 if(this.vDomScrollHeight - this.scrollTop > this.vDomWindowBuffer){
1499 this._removeBottomRow(-bottomDiff);
1507 if(this.scrollTop > this.vDomWindowBuffer){
1508 this._removeTopRow(topDiff);
1512 if(bottomDiff >= 0){
1513 this._addBottomRow(bottomDiff);
1519 RowManager.prototype._addTopRow =
function(topDiff, i=0){
1520 var table = this.tableElement,
1521 rows = this.getDisplayRows();
1524 let index = this.vDomTop -1,
1525 topRow = rows[index],
1526 topRowHeight = topRow.getHeight() || this.vDomRowHeight;
1529 if(topDiff >= topRowHeight){
1530 this.styleRow(topRow, index);
1531 table.insertBefore(topRow.getElement(), table.firstChild);
1532 if(!topRow.initialized || !topRow.heightInitialized){
1533 this.vDomTopNewRows.push(topRow);
1535 if(!topRow.heightInitialized){
1536 topRow.clearCellHeight();
1539 topRow.initialize();
1541 this.vDomTopPad -= topRowHeight;
1543 if(this.vDomTopPad < 0){
1544 this.vDomTopPad = index * this.vDomRowHeight;
1548 this.vDomTopPad = 0;
1551 table.style.paddingTop = this.vDomTopPad +
"px";
1552 this.vDomScrollPosTop -= topRowHeight;
1556 topDiff = -(this.scrollTop - this.vDomScrollPosTop);
1558 if(topRow.getHeight() > this.vDomWindowBuffer){
1559 this.vDomWindowBuffer = topRow.getHeight() * 2;
1562 if(i < this.vDomMaxRenderChain && this.vDomTop && topDiff >= (rows[this.vDomTop -1].getHeight() || this.vDomRowHeight)){
1563 this._addTopRow(topDiff, i+1);
1565 this._quickNormalizeRowHeight(this.vDomTopNewRows);
1572 RowManager.prototype._removeTopRow =
function(topDiff){
1573 var table = this.tableElement,
1574 topRow = this.getDisplayRows()[this.vDomTop],
1575 topRowHeight = topRow.getHeight() || this.vDomRowHeight;
1577 if(topDiff >= topRowHeight){
1579 var rowEl = topRow.getElement();
1580 rowEl.parentNode.removeChild(rowEl);
1582 this.vDomTopPad += topRowHeight;
1583 table.style.paddingTop = this.vDomTopPad +
"px";
1584 this.vDomScrollPosTop += this.vDomTop ? topRowHeight : topRowHeight + this.vDomWindowBuffer;
1587 topDiff = this.scrollTop - this.vDomScrollPosTop;
1589 this._removeTopRow(topDiff);
1594 RowManager.prototype._addBottomRow =
function(bottomDiff, i=0){
1595 var table = this.tableElement,
1596 rows = this.getDisplayRows();
1598 if(this.vDomBottom < this.displayRowsCount -1){
1599 let index = this.vDomBottom + 1,
1600 bottomRow = rows[index],
1601 bottomRowHeight = bottomRow.getHeight() || this.vDomRowHeight;
1604 if(bottomDiff >= bottomRowHeight){
1605 this.styleRow(bottomRow, index);
1606 table.appendChild(bottomRow.getElement());
1608 if(!bottomRow.initialized || !bottomRow.heightInitialized){
1609 this.vDomBottomNewRows.push(bottomRow);
1611 if(!bottomRow.heightInitialized){
1612 bottomRow.clearCellHeight();
1616 bottomRow.initialize();
1618 this.vDomBottomPad -= bottomRowHeight;
1620 if(this.vDomBottomPad < 0 || index == this.displayRowsCount -1){
1621 this.vDomBottomPad = 0;
1624 table.style.paddingBottom = this.vDomBottomPad +
"px";
1625 this.vDomScrollPosBottom += bottomRowHeight;
1629 bottomDiff = this.scrollTop - this.vDomScrollPosBottom;
1631 if(bottomRow.getHeight() > this.vDomWindowBuffer){
1632 this.vDomWindowBuffer = bottomRow.getHeight() * 2;
1635 if(i < this.vDomMaxRenderChain && this.vDomBottom < this.displayRowsCount -1 && bottomDiff >= (rows[this.vDomBottom + 1].getHeight() || this.vDomRowHeight)){
1636 this._addBottomRow(bottomDiff, i+1);
1638 this._quickNormalizeRowHeight(this.vDomBottomNewRows);
1643 RowManager.prototype._removeBottomRow =
function(bottomDiff){
1644 var table = this.tableElement,
1645 bottomRow = this.getDisplayRows()[this.vDomBottom],
1646 bottomRowHeight = bottomRow.getHeight() || this.vDomRowHeight;
1648 if(bottomDiff >= bottomRowHeight){
1650 var rowEl = bottomRow.getElement();
1652 if(rowEl.parentNode){
1653 rowEl.parentNode.removeChild(rowEl);
1656 this.vDomBottomPad += bottomRowHeight;
1658 if(this.vDomBottomPad < 0){
1659 this.vDomBottomPad = 0;
1662 table.style.paddingBottom = this.vDomBottomPad +
"px";
1663 this.vDomScrollPosBottom -= bottomRowHeight;
1666 bottomDiff = -(this.scrollTop - this.vDomScrollPosBottom);
1668 this._removeBottomRow(bottomDiff);
1672 RowManager.prototype._quickNormalizeRowHeight =
function(rows){
1673 rows.forEach(
function(row){
1677 rows.forEach(
function(row){
1678 row.setCellHeight();
1685 RowManager.prototype.normalizeHeight =
function(){
1686 this.activeRows.forEach(
function(row){
1687 row.normalizeHeight();
1692 RowManager.prototype.adjustTableSize =
function(){
1694 if(this.renderMode ===
"virtual"){
1695 this.height = this.element.clientHeight;
1696 this.vDomWindowBuffer = this.table.options.virtualDomBuffer || this.height;
1698 let otherHeight = this.columnManager.getElement().offsetHeight + (this.table.footerManager && !this.table.footerManager.external ? this.table.footerManager.getElement().offsetHeight : 0);
1700 this.element.style.minHeight =
"calc(100% - " + otherHeight +
"px)";
1701 this.element.style.height =
"calc(100% - " + otherHeight +
"px)";
1702 this.element.style.maxHeight =
"calc(100% - " + otherHeight +
"px)";
1707 RowManager.prototype.reinitialize =
function(){
1708 this.rows.forEach(
function(row){
1714 RowManager.prototype.blockRedraw =
function (){
1715 this.redrawBlock =
true;
1716 this.redrawBlockRestoreConfig =
false;
1720 RowManager.prototype.restoreRedraw =
function (){
1721 this.redrawBlock =
false;
1724 if(this.redrawBlockRestoreConfig){
1725 this.refreshActiveData(this.redrawBlockRestoreConfig.stage,
this.redrawBlockRestoreConfig.skipStage,
this.redrawBlockRestoreConfig.renderInPosition)
1727 this.redrawBlockRestoreConfig = false;
1729 if(this.redrawBlockRederInPosition){
1730 this.reRenderInPosition();
1734 this.redrawBlockRederInPosition =
false;
1739 RowManager.prototype.redraw =
function (force){
1741 left = this.scrollLeft;
1743 this.adjustTableSize();
1745 this.table.tableWidth = this.table.element.clientWidth;
1748 if(this.renderMode ==
"classic"){
1750 if(this.table.options.groupBy){
1751 this.refreshActiveData(
"group",
false,
false);
1753 this._simpleRender();
1757 this.reRenderInPosition();
1758 this.scrollHorizontal(left);
1761 if(!this.displayRowsCount){
1762 if(this.table.options.placeholder){
1763 this.getElement().appendChild(this.table.options.placeholder);
1772 RowManager.prototype.resetScroll =
function(){
1773 this.element.scrollLeft = 0;
1774 this.element.scrollTop = 0;
1776 if(this.table.browser ===
"ie"){
1777 var
event = document.createEvent(
"Event");
1778 event.initEvent(
"scroll",
false,
true);
1779 this.element.dispatchEvent(event);
1781 this.element.dispatchEvent(
new Event(
'scroll'));