org.dominokit.domino.ui.datatable.plugins.GroupingPlugin Maven / Gradle / Ivy
/*
* Copyright © 2019 Dominokit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dominokit.domino.ui.datatable.plugins;
import static java.util.Objects.nonNull;
import static org.dominokit.domino.ui.style.Unit.px;
import static org.jboss.elemento.Elements.td;
import static org.jboss.elemento.Elements.tr;
import elemental2.dom.HTMLTableCellElement;
import elemental2.dom.Node;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.dominokit.domino.ui.datatable.CellRenderer;
import org.dominokit.domino.ui.datatable.DataTable;
import org.dominokit.domino.ui.datatable.TableConfig;
import org.dominokit.domino.ui.datatable.TableRow;
import org.dominokit.domino.ui.datatable.events.OnBeforeDataChangeEvent;
import org.dominokit.domino.ui.datatable.events.TableEvent;
import org.dominokit.domino.ui.grid.flex.FlexItem;
import org.dominokit.domino.ui.grid.flex.FlexLayout;
import org.dominokit.domino.ui.icons.BaseIcon;
import org.dominokit.domino.ui.icons.Icons;
import org.dominokit.domino.ui.utils.DominoElement;
/**
* This plugin renders the table rows in groups.
*
* @param the type of the data table records
*/
public class GroupingPlugin implements DataTablePlugin, TableConfig.RowAppender {
private Map> dataGroups = new HashMap<>();
private final GroupSupplier groupSupplier;
private CellRenderer groupRenderer;
private Supplier> groupExpandedIconSupplier = Icons.ALL::minus_box_mdi;
private Supplier> groupCollapsedIconSupplier = Icons.ALL::plus_box_mdi;
/**
* Create an instance with custom group supplier and group cell renderer
*
* @param groupSupplier the {@link GroupSupplier}
* @param groupRenderer the {@link CellRenderer}
*/
public GroupingPlugin(GroupSupplier groupSupplier, CellRenderer groupRenderer) {
this.groupSupplier = groupSupplier;
this.groupRenderer = groupRenderer;
}
/** {@inheritDoc} */
@Override
public void init(DataTable dataTable) {
dataTable.getTableConfig().setRowAppender(this);
}
/**
* Changes the group expand icon
*
* @param groupExpandedIconSupplier Supplier of {@link BaseIcon} to change the icon
* @return same plugin instance
*/
public GroupingPlugin setGroupExpandedIcon(Supplier> groupExpandedIconSupplier) {
this.groupExpandedIconSupplier = groupExpandedIconSupplier;
return this;
}
/**
* Changes the group collapse icon
*
* @param groupCollapsedIconSupplier Supplier of {@link BaseIcon} to change the icon
* @return same plugin instance
*/
public GroupingPlugin setGroupCollapsedIcon(Supplier> groupCollapsedIconSupplier) {
this.groupCollapsedIconSupplier = groupCollapsedIconSupplier;
return this;
}
/**
* {@inheritDoc}
*
* the plugin will create a group based on the GroupSupplier and will append rows to the first
* group matching the criteria
*/
@Override
public void appendRow(DataTable dataTable, TableRow tableRow) {
String groupId = groupSupplier.getRecordGroupId(tableRow);
if (!dataGroups.containsKey(groupId)) {
HTMLTableCellElement cellElement =
td().attr("colspan", dataTable.getTableConfig().getColumns().size() + "").element();
CellRenderer.CellInfo cellInfo = new CellRenderer.CellInfo<>(tableRow, cellElement);
DataGroup dataGroup = new DataGroup<>(tableRow, cellInfo);
BaseIcon> groupIconSupplier =
groupExpandedIconSupplier
.get()
.clickable()
.setToggleIcon(groupCollapsedIconSupplier.get())
.toggleOnClick(true)
.addClickListener(evt -> dataGroup.toggleGroup());
dataGroup.setGroupIconSupplier(groupIconSupplier).setGroupRenderer(groupRenderer).render();
dataTable.bodyElement().appendChild(tr().add(cellElement));
dataTable.bodyElement().appendChild(tableRow.element());
dataGroups.put(groupId, dataGroup);
} else {
DataGroup dataGroup = dataGroups.get(groupId);
Node nextSibling = dataGroup.lastRow.element().nextSibling;
if (nonNull(nextSibling)) {
DominoElement.of(dataTable.bodyElement()).insertBefore(tableRow.element(), nextSibling);
} else {
dataTable.bodyElement().appendChild(tableRow.element());
}
dataGroup.lastRow = tableRow;
dataGroup.addRow(tableRow);
}
}
/** Expands all the current groups in the data table */
public void expandAll() {
for (DataGroup dataGroup : dataGroups.values()) {
if (!dataGroup.expanded) {
dataGroup.toggleGroup();
dataGroup.getGroupIconSupplier().toggleIcon();
}
}
}
/** Collapse all the current groups in the data table */
public void collapseAll() {
for (DataGroup dataGroup : dataGroups.values()) {
if (dataGroup.expanded) {
dataGroup.toggleGroup();
dataGroup.getGroupIconSupplier().toggleIcon();
}
}
}
public Map> getDataGroups() {
return dataGroups;
}
/** {@inheritDoc} */
@Override
public void handleEvent(TableEvent event) {
if (event.getType().equalsIgnoreCase(OnBeforeDataChangeEvent.ON_BEFORE_DATA_CHANGE)) {
dataGroups.clear();
}
}
public static class DataGroup implements TableRow.RowMetaObject {
private static final String KEY = "dataGroup";
private List> groupRows = new ArrayList<>();
private TableRow lastRow;
private CellRenderer.CellInfo cellInfo;
private boolean expanded = true;
private BaseIcon> groupIconSupplier;
private CellRenderer groupRenderer;
public DataGroup(TableRow lastRow, CellRenderer.CellInfo cellInfo) {
this.lastRow = lastRow;
this.cellInfo = cellInfo;
addRow(lastRow);
}
public static DataGroup fromRow(TableRow tableRow) {
return tableRow.getMetaObject(KEY);
}
public void toggleGroup() {
expanded = !expanded;
groupRows.forEach(tableRow -> DominoElement.of(tableRow.element()).toggleDisplay(expanded));
}
public void addRow(TableRow tableRow) {
groupRows.add(tableRow);
tableRow.addMetaObject(this);
}
private DataGroup setGroupIconSupplier(BaseIcon> groupIconSupplier) {
this.groupIconSupplier = groupIconSupplier;
return this;
}
private BaseIcon> getGroupIconSupplier() {
return this.groupIconSupplier;
}
private DataGroup setGroupRenderer(CellRenderer groupRenderer) {
this.groupRenderer = groupRenderer;
return this;
}
@Override
public String getKey() {
return KEY;
}
public void render() {
DominoElement.of(cellInfo.getElement())
.clearElement()
.appendChild(
FlexLayout.create()
.appendChild(FlexItem.create().appendChild(groupIconSupplier))
.appendChild(
FlexItem.create()
.styler(style -> style.setLineHeight(px.of(35)).setPaddingLeft(px.of(10)))
.setFlexGrow(1)
.appendChild(groupRenderer.asElement(cellInfo))));
}
}
/**
* this interface is to provide an implementation to define each row group
*
* @param the type of the table row record
*/
@FunctionalInterface
public interface GroupSupplier {
/**
* determines the row group
*
* @param tableRow the {@link TableRow}
* @return String group name the table row belongs to
*/
String getRecordGroupId(TableRow tableRow);
}
}