4 var GroupComponent =
function GroupComponent(group) {
6 this.type =
"GroupComponent";
9 GroupComponent.prototype.getKey =
function () {
10 return this._group.key;
13 GroupComponent.prototype.getField =
function () {
14 return this._group.field;
17 GroupComponent.prototype.getElement =
function () {
18 return this._group.element;
21 GroupComponent.prototype.getRows =
function () {
22 return this._group.getRows(
true);
25 GroupComponent.prototype.getSubGroups =
function () {
26 return this._group.getSubGroups(
true);
29 GroupComponent.prototype.getParentGroup =
function () {
30 return this._group.parent ? this._group.parent.getComponent() :
false;
33 GroupComponent.prototype.getVisibility =
function () {
34 return this._group.visible;
37 GroupComponent.prototype.show =
function () {
41 GroupComponent.prototype.hide =
function () {
45 GroupComponent.prototype.toggle =
function () {
46 this._group.toggleVisibility();
49 GroupComponent.prototype._getSelf =
function () {
53 GroupComponent.prototype.getTable =
function () {
54 return this._group.groupManager.table;
61 var Group =
function Group(groupManager, parent, level, key, field, generator, oldGroup) {
63 this.groupManager = groupManager;
68 this.hasSubGroups = level < groupManager.groupIDLookups.length - 1;
69 this.addRow = this.hasSubGroups ? this._addRowToGroup : this._addRow;
75 this.generator = generator;
76 this.elementContents =
false;
79 this.initialized =
false;
81 this.initialized =
false;
83 this.arrowElement =
false;
85 this.visible = oldGroup ? oldGroup.visible : typeof groupManager.startOpen[level] !==
"undefined" ? groupManager.startOpen[level] : groupManager.startOpen[0];
87 this.createElements();
90 this.createValueGroups();
93 Group.prototype.wipe =
function () {
94 if (this.groupList.length) {
95 this.groupList.forEach(
function (group) {
100 this.arrowElement =
false;
101 this.elementContents =
false;
105 Group.prototype.createElements =
function () {
106 var arrow = document.createElement(
"div");
107 arrow.classList.add(
"tabulator-arrow");
109 this.element = document.createElement(
"div");
110 this.element.classList.add(
"tabulator-row");
111 this.element.classList.add(
"tabulator-group");
112 this.element.classList.add(
"tabulator-group-level-" + this.level);
113 this.element.setAttribute(
"role",
"rowgroup");
115 this.arrowElement = document.createElement(
"div");
116 this.arrowElement.classList.add(
"tabulator-group-toggle");
117 this.arrowElement.appendChild(arrow);
120 if (this.groupManager.table.options.movableRows !==
false &&
this.groupManager.table.modExists(
"moveRow")) {
121 this.groupManager.table.modules.moveRow.initializeGroupHeader(
this);
125 Group.prototype.createValueGroups =
function () {
128 var level = this.level + 1;
129 if (this.groupManager.allowedValues &&
this.groupManager.allowedValues[level]) {
130 this.groupManager.allowedValues[level].forEach(
function (value) {
131 _this._createGroup(value, level);
136 Group.prototype.addBindings =
function () {
144 if (
self.groupManager.table.options.groupClick) {
145 self.element.addEventListener(
"click",
function (e) {
146 self.groupManager.table.options.groupClick.call(
self.groupManager.table, e,
self.getComponent());
150 if (
self.groupManager.table.options.groupDblClick) {
151 self.element.addEventListener(
"dblclick",
function (e) {
152 self.groupManager.table.options.groupDblClick.call(
self.groupManager.table, e,
self.getComponent());
156 if (
self.groupManager.table.options.groupContext) {
157 self.element.addEventListener(
"contextmenu",
function (e) {
158 self.groupManager.table.options.groupContext.call(
self.groupManager.table, e,
self.getComponent());
162 if (
self.groupManager.table.options.groupTap) {
166 self.element.addEventListener(
"touchstart",
function (e) {
168 }, { passive:
true });
170 self.element.addEventListener(
"touchend",
function (e) {
172 self.groupManager.table.options.groupTap(e,
self.getComponent());
179 if (
self.groupManager.table.options.groupDblTap) {
183 self.element.addEventListener(
"touchend",
function (e) {
186 clearTimeout(dblTap);
189 self.groupManager.table.options.groupDblTap(e,
self.getComponent());
192 dblTap = setTimeout(
function () {
193 clearTimeout(dblTap);
200 if (
self.groupManager.table.options.groupTapHold) {
204 self.element.addEventListener(
"touchstart",
function (e) {
205 clearTimeout(tapHold);
207 tapHold = setTimeout(
function () {
208 clearTimeout(tapHold);
211 self.groupManager.table.options.groupTapHold(e,
self.getComponent());
213 }, { passive:
true });
215 self.element.addEventListener(
"touchend",
function (e) {
216 clearTimeout(tapHold);
221 if (
self.groupManager.table.options.groupToggleElement) {
222 toggleElement =
self.groupManager.table.options.groupToggleElement ==
"arrow" ?
self.arrowElement :
self.element;
224 toggleElement.addEventListener(
"click",
function (e) {
226 e.stopImmediatePropagation();
227 self.toggleVisibility();
232 Group.prototype._createGroup =
function (groupID, level) {
233 var groupKey = level +
"_" + groupID;
234 var group =
new Group(this.groupManager,
this, level, groupID, this.groupManager.groupIDLookups[level].field,
this.groupManager.headerGenerator[level] ||
this.groupManager.headerGenerator[0],
this.old ?
this.old.groups[groupKey] :
false);
236 this.groups[groupKey] = group;
237 this.groupList.push(group);
240 Group.prototype._addRowToGroup =
function (row) {
242 var level = this.level + 1;
244 if (this.hasSubGroups) {
245 var groupID = this.groupManager.groupIDLookups[level].func(row.getData()),
246 groupKey = level +
"_" + groupID;
248 if (this.groupManager.allowedValues &&
this.groupManager.allowedValues[level]) {
249 if (this.groups[groupKey]) {
250 this.groups[groupKey].addRow(row);
253 if (!this.groups[groupKey]) {
254 this._createGroup(groupID, level);
257 this.groups[groupKey].addRow(row);
262 Group.prototype._addRow =
function (row) {
264 row.modules.group =
this;
267 Group.prototype.insertRow =
function (row, to, after) {
268 var data = this.conformRowData({});
270 row.updateData(data);
272 var toIndex = this.rows.indexOf(to);
276 this.rows.splice(toIndex + 1, 0, row);
278 this.rows.splice(toIndex, 0, row);
284 this.rows.unshift(row);
288 row.modules.group =
this;
290 this.generateGroupHeaderContents();
292 if (this.groupManager.table.modExists(
"columnCalcs") && this.groupManager.table.options.columnCalcs !=
"table") {
293 this.groupManager.table.modules.columnCalcs.recalcGroup(
this);
296 this.groupManager.updateGroupRows(
true);
299 Group.prototype.scrollHeader =
function (left) {
300 this.arrowElement.style.marginLeft = left;
302 this.groupList.forEach(
function (child) {
303 child.scrollHeader(left);
307 Group.prototype.getRowIndex =
function (row) {};
310 Group.prototype.conformRowData =
function (data) {
312 data[this.field] = this.key;
314 console.warn(
"Data Conforming Error - Cannot conform row data to match new group as groupBy is a function");
318 data = this.parent.conformRowData(data);
324 Group.prototype.removeRow =
function (row) {
325 var index = this.rows.indexOf(row);
326 var el = row.getElement();
329 this.rows.splice(index, 1);
332 if (!this.groupManager.table.options.groupValues && !
this.rows.length) {
334 this.parent.removeGroup(
this);
336 this.groupManager.removeGroup(
this);
339 this.groupManager.updateGroupRows(
true);
343 el.parentNode.removeChild(el);
346 this.generateGroupHeaderContents();
348 if (this.groupManager.table.modExists(
"columnCalcs") && this.groupManager.table.options.columnCalcs !=
"table") {
349 this.groupManager.table.modules.columnCalcs.recalcGroup(
this);
354 Group.prototype.removeGroup =
function (group) {
355 var groupKey = group.level +
"_" + group.key,
358 if (this.groups[groupKey]) {
359 delete this.groups[groupKey];
361 index = this.groupList.indexOf(group);
364 this.groupList.splice(index, 1);
367 if (!this.groupList.length) {
369 this.parent.removeGroup(
this);
371 this.groupManager.removeGroup(
this);
377 Group.prototype.getHeadersAndRows =
function (noCalc) {
385 if (this.groupList.length) {
386 this.groupList.forEach(
function (group) {
387 output = output.concat(group.getHeadersAndRows(noCalc));
390 if (!noCalc && this.groupManager.table.options.columnCalcs !=
"table" &&
this.groupManager.table.modExists(
"columnCalcs") && this.groupManager.table.modules.columnCalcs.hasTopCalcs()) {
391 if (this.calcs.top) {
392 this.calcs.top.detachElement();
393 this.calcs.top.deleteCells();
396 this.calcs.top = this.groupManager.table.modules.columnCalcs.generateTopRow(this.rows);
397 output.push(this.calcs.top);
400 output = output.concat(this.rows);
402 if (!noCalc && this.groupManager.table.options.columnCalcs !=
"table" &&
this.groupManager.table.modExists(
"columnCalcs") && this.groupManager.table.modules.columnCalcs.hasBottomCalcs()) {
403 if (this.calcs.bottom) {
404 this.calcs.bottom.detachElement();
405 this.calcs.bottom.deleteCells();
408 this.calcs.bottom = this.groupManager.table.modules.columnCalcs.generateBottomRow(this.rows);
409 output.push(this.calcs.bottom);
413 if (!this.groupList.length &&
this.groupManager.table.options.columnCalcs !=
"table") {
415 if (this.groupManager.table.modExists(
"columnCalcs")) {
417 if (!noCalc && this.groupManager.table.modules.columnCalcs.hasTopCalcs()) {
418 if (this.calcs.top) {
419 this.calcs.top.detachElement();
420 this.calcs.top.deleteCells();
423 if (this.groupManager.table.options.groupClosedShowCalcs) {
424 this.calcs.top = this.groupManager.table.modules.columnCalcs.generateTopRow(this.rows);
425 output.push(this.calcs.top);
429 if (!noCalc && this.groupManager.table.modules.columnCalcs.hasBottomCalcs()) {
430 if (this.calcs.bottom) {
431 this.calcs.bottom.detachElement();
432 this.calcs.bottom.deleteCells();
435 if (this.groupManager.table.options.groupClosedShowCalcs) {
436 this.calcs.bottom = this.groupManager.table.modules.columnCalcs.generateBottomRow(this.rows);
437 output.push(this.calcs.bottom);
447 Group.prototype.getData =
function (visible, transform) {
453 if (!visible || visible && this.visible) {
454 this.rows.forEach(
function (row) {
455 output.push(row.getData(transform ||
"data"));
468 Group.prototype.getRowCount =
function () {
471 if (this.groupList.length) {
472 this.groupList.forEach(
function (group) {
473 count += group.getRowCount();
476 count = this.rows.length;
481 Group.prototype.toggleVisibility =
function () {
489 Group.prototype.hide =
function () {
490 this.visible =
false;
492 if (this.groupManager.table.rowManager.getRenderMode() ==
"classic" && !this.groupManager.table.options.pagination) {
494 this.element.classList.remove(
"tabulator-group-visible");
496 if (this.groupList.length) {
497 this.groupList.forEach(
function (group) {
499 var rows = group.getHeadersAndRows();
501 rows.forEach(
function (row) {
506 this.rows.forEach(
function (row) {
507 var rowEl = row.getElement();
508 rowEl.parentNode.removeChild(rowEl);
512 this.groupManager.table.rowManager.setDisplayRows(this.groupManager.updateGroupRows(), this.groupManager.getDisplayIndex());
514 this.groupManager.table.rowManager.checkClassicModeGroupHeaderWidth();
516 this.groupManager.updateGroupRows(
true);
519 this.groupManager.table.options.groupVisibilityChanged.call(this.table, this.getComponent(),
false);
522 Group.prototype.show =
function () {
527 if (this.groupManager.table.rowManager.getRenderMode() ==
"classic" && !this.groupManager.table.options.pagination) {
529 this.element.classList.add(
"tabulator-group-visible");
531 var prev =
self.getElement();
533 if (this.groupList.length) {
534 this.groupList.forEach(
function (group) {
535 var rows = group.getHeadersAndRows();
537 rows.forEach(
function (row) {
538 var rowEl = row.getElement();
539 prev.parentNode.insertBefore(rowEl, prev.nextSibling);
545 self.rows.forEach(
function (row) {
546 var rowEl = row.getElement();
547 prev.parentNode.insertBefore(rowEl, prev.nextSibling);
553 this.groupManager.table.rowManager.setDisplayRows(this.groupManager.updateGroupRows(), this.groupManager.getDisplayIndex());
555 this.groupManager.table.rowManager.checkClassicModeGroupHeaderWidth();
557 this.groupManager.updateGroupRows(
true);
560 this.groupManager.table.options.groupVisibilityChanged.call(this.table, this.getComponent(),
true);
563 Group.prototype._visSet =
function () {
566 if (typeof this.visible ==
"function") {
568 this.rows.forEach(
function (row) {
569 data.push(row.getData());
572 this.visible = this.visible(this.key, this.getRowCount(), data, this.getComponent());
576 Group.prototype.getRowGroup =
function (row) {
578 if (this.groupList.length) {
579 this.groupList.forEach(
function (group) {
580 var result = group.getRowGroup(row);
587 if (this.rows.find(function (item) {
597 Group.prototype.getSubGroups =
function (component) {
600 this.groupList.forEach(
function (child) {
601 output.push(component ? child.getComponent() : child);
607 Group.prototype.getRows =
function (compoment) {
610 this.rows.forEach(
function (row) {
611 output.push(compoment ? row.getComponent() : row);
617 Group.prototype.generateGroupHeaderContents =
function () {
620 this.rows.forEach(
function (row) {
621 data.push(row.getData());
624 this.elementContents = this.generator(this.key, this.getRowCount(), data, this.getComponent());
626 while (this.element.firstChild) {
627 this.element.removeChild(this.element.firstChild);
628 }
if (typeof this.elementContents ===
"string") {
629 this.element.innerHTML = this.elementContents;
631 this.element.appendChild(this.elementContents);
634 this.element.insertBefore(this.arrowElement, this.element.firstChild);
639 Group.prototype.getElement =
function () {
640 this.addBindingsd =
false;
645 this.element.classList.add(
"tabulator-group-visible");
647 this.element.classList.remove(
"tabulator-group-visible");
650 for (var i = 0; i < this.element.childNodes.length; ++i) {
651 this.element.childNodes[i].parentNode.removeChild(this.element.childNodes[i]);
654 this.generateGroupHeaderContents();
661 Group.prototype.detachElement =
function () {
662 if (this.element && this.element.parentNode) {
663 this.element.parentNode.removeChild(this.element);
668 Group.prototype.normalizeHeight =
function () {
669 this.setHeight(this.element.clientHeight);
672 Group.prototype.initialize =
function (force) {
673 if (!this.initialized || force) {
674 this.normalizeHeight();
675 this.initialized =
true;
679 Group.prototype.reinitialize =
function () {
680 this.initialized =
false;
683 if (Tabulator.prototype.helpers.elVisible(
this.element)) {
684 this.initialize(
true);
688 Group.prototype.setHeight =
function (height) {
689 if (this.height != height) {
690 this.height = height;
691 this.outerHeight = this.element.offsetHeight;
696 Group.prototype.getHeight =
function () {
697 return this.outerHeight;
700 Group.prototype.getGroup =
function () {
704 Group.prototype.reinitializeHeight =
function () {};
705 Group.prototype.calcHeight =
function () {};
706 Group.prototype.setCellHeight =
function () {};
707 Group.prototype.clearCellHeight =
function () {};
710 Group.prototype.getComponent =
function () {
711 return new GroupComponent(
this);
718 var GroupRows =
function GroupRows(table) {
722 this.groupIDLookups =
false;
723 this.startOpen = [
function () {
726 this.headerGenerator = [
function () {
730 this.allowedValues =
false;
732 this.displayIndex = 0;
736 GroupRows.prototype.initialize =
function () {
738 groupBy =
self.table.options.groupBy,
739 startOpen =
self.table.options.groupStartOpen,
740 groupHeader =
self.table.options.groupHeader;
742 this.allowedValues =
self.table.options.groupValues;
744 if (Array.isArray(groupBy) && Array.isArray(groupHeader) && groupBy.length > groupHeader.length) {
745 console.warn(
"Error creating group headers, groupHeader array is shorter than groupBy array");
748 self.headerGenerator = [
function () {
751 this.startOpen = [
function () {
755 self.table.modules.localize.bind(
"groups|item",
function (langValue, lang) {
756 self.headerGenerator[0] =
function (value, count, data) {
758 return (typeof value ===
"undefined" ?
"" : value) +
"<span>(" + count +
" " + (count === 1 ? langValue : lang.groups.items) +
")</span>";
762 this.groupIDLookups = [];
764 if (Array.isArray(groupBy) || groupBy) {
765 if (this.table.modExists(
"columnCalcs") && this.table.options.columnCalcs !=
"table" && this.table.options.columnCalcs !=
"both") {
766 this.table.modules.columnCalcs.removeCalcs();
769 if (this.table.modExists(
"columnCalcs") && this.table.options.columnCalcs !=
"group") {
771 var cols = this.table.columnManager.getRealColumns();
773 cols.forEach(
function (col) {
774 if (col.definition.topCalc) {
775 self.table.modules.columnCalcs.initializeTopRow();
778 if (col.definition.bottomCalc) {
779 self.table.modules.columnCalcs.initializeBottomRow();
785 if (!Array.isArray(groupBy)) {
789 groupBy.forEach(
function (group, i) {
790 var lookupFunc, column;
792 if (typeof group ==
"function") {
795 column =
self.table.columnManager.getColumnByField(group);
798 lookupFunc =
function lookupFunc(data) {
799 return column.getFieldValue(data);
802 lookupFunc =
function lookupFunc(data) {
808 self.groupIDLookups.push({
809 field: typeof group ===
"function" ?
false : group,
811 values:
self.allowedValues ?
self.allowedValues[i] :
false
817 if (!Array.isArray(startOpen)) {
818 startOpen = [startOpen];
821 startOpen.forEach(
function (level) {
822 level = typeof level ==
"function" ? level :
function () {
827 self.startOpen = startOpen;
831 self.headerGenerator = Array.isArray(groupHeader) ? groupHeader : [groupHeader];
834 this.initialized =
true;
837 GroupRows.prototype.setDisplayIndex =
function (index) {
838 this.displayIndex = index;
841 GroupRows.prototype.getDisplayIndex =
function () {
842 return this.displayIndex;
846 GroupRows.prototype.getRows =
function (rows) {
847 if (this.groupIDLookups.length) {
849 this.table.options.dataGrouping.call(this.table);
851 this.generateGroups(rows);
853 if (this.table.options.dataGrouped) {
854 this.table.options.dataGrouped.call(this.table, this.getGroups(
true));
857 return this.updateGroupRows();
859 return rows.slice(0);
863 GroupRows.prototype.getGroups =
function (compoment) {
864 var groupComponents = [];
866 this.groupList.forEach(
function (group) {
867 groupComponents.push(compoment ? group.getComponent() : group);
870 return groupComponents;
873 GroupRows.prototype.wipe =
function () {
874 this.groupList.forEach(
function (group) {
879 GroupRows.prototype.pullGroupListData =
function (groupList) {
881 var groupListData = [];
883 groupList.forEach(
function (group) {
884 var groupHeader = {};
885 groupHeader.level = 0;
886 groupHeader.rowCount = 0;
887 groupHeader.headerContent =
"";
890 if (group.hasSubGroups) {
891 childData =
self.pullGroupListData(group.groupList);
893 groupHeader.level = group.level;
894 groupHeader.rowCount = childData.length - group.groupList.length;
895 groupHeader.headerContent = group.generator(group.key, groupHeader.rowCount, group.rows, group);
897 groupListData.push(groupHeader);
898 groupListData = groupListData.concat(childData);
900 groupHeader.level = group.level;
901 groupHeader.headerContent = group.generator(group.key, group.rows.length, group.rows, group);
902 groupHeader.rowCount = group.getRows().length;
904 groupListData.push(groupHeader);
906 group.getRows().forEach(
function (row) {
907 groupListData.push(row.getData(
"data"));
912 return groupListData;
915 GroupRows.prototype.getGroupedData =
function () {
917 return this.pullGroupListData(this.groupList);
920 GroupRows.prototype.getRowGroup =
function (row) {
923 this.groupList.forEach(
function (group) {
924 var result = group.getRowGroup(row);
934 GroupRows.prototype.countGroups =
function () {
935 return this.groupList.length;
938 GroupRows.prototype.generateGroups =
function (rows) {
940 oldGroups =
self.groups;
945 if (this.allowedValues && this.allowedValues[0]) {
946 this.allowedValues[0].forEach(
function (value) {
947 self.createGroup(value, 0, oldGroups);
950 rows.forEach(
function (row) {
951 self.assignRowToExistingGroup(row, oldGroups);
954 rows.forEach(
function (row) {
955 self.assignRowToGroup(row, oldGroups);
960 GroupRows.prototype.createGroup =
function (groupID, level, oldGroups) {
961 var groupKey = level +
"_" + groupID,
964 oldGroups = oldGroups || [];
966 group =
new Group(
this,
false, level, groupID, this.groupIDLookups[0].field, this.headerGenerator[0], oldGroups[groupKey]);
968 this.groups[groupKey] = group;
969 this.groupList.push(group);
983 GroupRows.prototype.assignRowToExistingGroup =
function (row, oldGroups) {
984 var groupID = this.groupIDLookups[0].func(row.getData()),
985 groupKey =
"0_" + groupID;
987 if (this.groups[groupKey]) {
988 this.groups[groupKey].addRow(row);
992 GroupRows.prototype.assignRowToGroup =
function (row, oldGroups) {
993 var groupID = this.groupIDLookups[0].func(row.getData()),
994 newGroupNeeded = !this.groups[
"0_" + groupID];
996 if (newGroupNeeded) {
997 this.createGroup(groupID, 0, oldGroups);
1000 this.groups[
"0_" + groupID].addRow(row);
1002 return !newGroupNeeded;
1005 GroupRows.prototype.updateGroupRows =
function (force) {
1010 self.groupList.forEach(
function (group) {
1011 output = output.concat(group.getHeadersAndRows());
1017 var displayIndex =
self.table.rowManager.setDisplayRows(output, this.getDisplayIndex());
1019 if (displayIndex !==
true) {
1020 this.setDisplayIndex(displayIndex);
1023 self.table.rowManager.refreshActiveData(
"group",
true,
true);
1029 GroupRows.prototype.scrollHeaders =
function (left) {
1032 this.groupList.forEach(
function (group) {
1033 group.scrollHeader(left);
1037 GroupRows.prototype.removeGroup =
function (group) {
1038 var groupKey = group.level +
"_" + group.key,
1041 if (this.groups[groupKey]) {
1042 delete this.groups[groupKey];
1044 index = this.groupList.indexOf(group);
1047 this.groupList.splice(index, 1);
1052 Tabulator.prototype.registerModule(
"groupRows", GroupRows);