Skip to content

Commit

Permalink
Fixed #1120 - Support the shift key for multiple selection in TreeTab…
Browse files Browse the repository at this point in the history
…le (#1728)

* Support the shift key for multiple selection in TreeTable

* Revert to resolve conflict

Co-authored-by: Phong Le <[email protected]>
  • Loading branch information
pholeth and Phong Le authored Nov 3, 2021
1 parent cb4dea3 commit 427982e
Show file tree
Hide file tree
Showing 2 changed files with 178 additions and 117 deletions.
178 changes: 177 additions & 1 deletion src/components/treetable/TreeTableBody.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import DomHandler from '../utils/DomHandler';
import { TreeTableRow } from './TreeTableRow';

export class TreeTableBody extends Component {
Expand Down Expand Up @@ -60,19 +61,194 @@ export class TreeTableBody extends Component {
onContextMenu: PropTypes.func
}

constructor(props) {
super(props);

this.onRowClick = this.onRowClick.bind(this);
}

createRow(node, index) {
return (
<TreeTableRow key={node.key||JSON.stringify(node.data)} level={0} rowIndex={index} selectOnEdit={this.props.selectOnEdit}
node={node} columns={this.props.columns} expandedKeys={this.props.expandedKeys}
onToggle={this.props.onToggle} onExpand={this.props.onExpand} onCollapse={this.props.onCollapse}
selectionMode={this.props.selectionMode} selectionKeys={this.props.selectionKeys} onSelectionChange={this.props.onSelectionChange}
metaKeySelection={this.props.metaKeySelection} onRowClick={this.props.onRowClick} onSelect={this.props.onSelect} onUnselect={this.props.onUnselect}
metaKeySelection={this.props.metaKeySelection} onRowClick={this.onRowClick} onSelect={this.props.onSelect} onUnselect={this.props.onUnselect}
propagateSelectionUp={this.props.propagateSelectionUp} propagateSelectionDown={this.props.propagateSelectionDown}
rowClassName={this.props.rowClassName}
contextMenuSelectionKey={this.props.contextMenuSelectionKey} onContextMenuSelectionChange={this.props.onContextMenuSelectionChange} onContextMenu={this.props.onContextMenu} />
);
}

flattenizeTree(nodes) {
let rows = [];
nodes = nodes || this.props.value;

for (let node of nodes) {
rows.push(node.key);

if (this.isExpandedKey(node.key)) {
rows = rows.concat(this.flattenizeTree(node.children));
}
}

return rows;
}

isExpandedKey(key) {
return this.props.expandedKeys && !!this.props.expandedKeys[key];
}

onRowClick(event, node) {

if (this.props.onRowClick) {
this.props.onRowClick({
originalEvent: event,
node: node
});
}

let targetNode = event.target.nodeName;
if (targetNode === 'INPUT' || targetNode === 'BUTTON' || targetNode === 'A' || DomHandler.hasClass(event.target, 'p-clickable')
|| DomHandler.hasClass(event.target, 'p-treetable-toggler') || DomHandler.hasClass(event.target.parentElement, 'p-treetable-toggler')) {
return;
}

if ((this.isSingleSelectionMode() || this.isMultipleSelectionMode()) && node.selectable !== false) {
let selectionKeys;
const selected = this.isSelected(node);
const metaSelection = this.nodeTouched ? false : this.props.metaKeySelection;
const flatKeys = this.flattenizeTree();
const rowIndex = flatKeys.findIndex(key => key === node.key);

if(this.isMultipleSelectionMode() && event.shiftKey) {
DomHandler.clearSelection();

// find first selected row
const anchorRowIndex = flatKeys.findIndex(key => this.props.selectionKeys[key]);
const rangeStart = Math.min(rowIndex, anchorRowIndex);
const rangeEnd = Math.max(rowIndex, anchorRowIndex);

selectionKeys = {...this.props.selectionKeys};

for (let i = rangeStart; i <= rangeEnd; i++) {
const rowKey = flatKeys[i];
selectionKeys[rowKey] = true;
}
}
else {
this.anchorRowIndex = rowIndex;

if (metaSelection) {
let metaKey = (event.metaKey||event.ctrlKey);

if (selected && metaKey) {
if (this.isSingleSelectionMode()) {
selectionKeys = null;
}
else {
selectionKeys = {...this.props.selectionKeys};
delete selectionKeys[node.key];
}

if (this.props.onUnselect) {
this.props.onUnselect({
originalEvent: event,
node: node
});
}
}
else {
if (this.isSingleSelectionMode()) {
selectionKeys = node.key;
}
else if (this.isMultipleSelectionMode()) {
selectionKeys = !metaKey ? {} : (this.props.selectionKeys ? {...this.props.selectionKeys} : {});
selectionKeys[node.key] = true;
}

if (this.props.onSelect) {
this.props.onSelect({
originalEvent: event,
node: node
});
}
}
}
else {
if (this.isSingleSelectionMode()) {
if (selected) {
selectionKeys = null;

if (this.props.onUnselect) {
this.props.onUnselect({
originalEvent: event,
node: node
});
}
}
else {
selectionKeys = node.key;

if (this.props.onSelect) {
this.props.onSelect({
originalEvent: event,
node: node
});
}
}
}
else {
if (selected) {
selectionKeys = {...this.props.selectionKeys};
delete selectionKeys[node.key];

if (this.props.onUnselect) {
this.props.onUnselect({
originalEvent: event,
node: node
});
}
}
else {
selectionKeys = this.props.selectionKeys ? {...this.props.selectionKeys} : {};
selectionKeys[node.key] = true;

if (this.props.onSelect) {
this.props.onSelect({
originalEvent: event,
node: node
});
}
}
}
}
}

if (this.props.onSelectionChange) {
this.props.onSelectionChange({
originalEvent: event,
value: selectionKeys
})
}
}
}

isSingleSelectionMode() {
return this.props.selectionMode && this.props.selectionMode === 'single';
}

isMultipleSelectionMode() {
return this.props.selectionMode && this.props.selectionMode === 'multiple';
}

isSelected(node) {
if ((this.props.selectionMode === 'single' || this.props.selectionMode === 'multiple') && this.props.selectionKeys)
return (this.props.selectionMode === 'single') ? this.props.selectionKeys === node.key : this.props.selectionKeys[node.key] !== undefined;
else
return false;
}

renderRows() {
if (this.props.paginator && !this.props.lazy) {
let rpp = this.props.rows||0;
Expand Down
117 changes: 1 addition & 116 deletions src/components/treetable/TreeTableRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,114 +127,7 @@ export class TreeTableRow extends Component {

onClick(event) {
if (this.props.onRowClick) {
this.props.onRowClick({
originalEvent: event,
node: this.props.node
});
}

let targetNode = event.target.nodeName;
if (targetNode === 'INPUT' || targetNode === 'BUTTON' || targetNode === 'A' || DomHandler.hasClass(event.target, 'p-clickable')
|| DomHandler.hasClass(event.target, 'p-treetable-toggler') || DomHandler.hasClass(event.target.parentElement, 'p-treetable-toggler')) {
return;
}

if ((this.isSingleSelectionMode() || this.isMultipleSelectionMode()) && this.props.node.selectable !== false) {
let selectionKeys;
const selected = this.isSelected();
const metaSelection = this.nodeTouched ? false : this.props.metaKeySelection;

if (metaSelection) {
let metaKey = (event.metaKey||event.ctrlKey);

if (selected && metaKey) {
if (this.isSingleSelectionMode()) {
selectionKeys = null;
}
else {
selectionKeys = {...this.props.selectionKeys};
delete selectionKeys[this.props.node.key];
}

if (this.props.onUnselect) {
this.props.onUnselect({
originalEvent: event,
node: this.props.node
});
}
}
else {
if (this.isSingleSelectionMode()) {
selectionKeys = this.props.node.key;
}
else if (this.isMultipleSelectionMode()) {
selectionKeys = !metaKey ? {} : (this.props.selectionKeys ? {...this.props.selectionKeys} : {});
selectionKeys[this.props.node.key] = true;
}

if (this.props.onSelect) {
this.props.onSelect({
originalEvent: event,
node: this.props.node
});
}
}
}
else {
if (this.isSingleSelectionMode()) {
if (selected) {
selectionKeys = null;

if (this.props.onUnselect) {
this.props.onUnselect({
originalEvent: event,
node: this.props.node
});
}
}
else {
selectionKeys = this.props.node.key;

if (this.props.onSelect) {
this.props.onSelect({
originalEvent: event,
node: this.props.node
});
}
}
}
else {
if (selected) {
selectionKeys = {...this.props.selectionKeys};
delete selectionKeys[this.props.node.key];

if (this.props.onUnselect) {
this.props.onUnselect({
originalEvent: event,
node: this.props.node
});
}
}
else {
selectionKeys = this.props.selectionKeys ? {...this.props.selectionKeys} : {};
selectionKeys[this.props.node.key] = true;

if (this.props.onSelect) {
this.props.onSelect({
originalEvent: event,
node: this.props.node
});
}
}
}
}

if (this.props.onSelectionChange) {
this.props.onSelectionChange({
originalEvent: event,
value: selectionKeys
})
}
this.props.onRowClick(event, this.props.node);
}

this.nodeTouched = false;
Expand Down Expand Up @@ -428,14 +321,6 @@ export class TreeTableRow extends Component {
}
}

isSingleSelectionMode() {
return this.props.selectionMode && this.props.selectionMode === 'single';
}

isMultipleSelectionMode() {
return this.props.selectionMode && this.props.selectionMode === 'multiple';
}

isExpanded() {
return this.props.expandedKeys ? this.props.expandedKeys[this.props.node.key] !== undefined : false;
}
Expand Down

0 comments on commit 427982e

Please sign in to comment.