Finished core functionality.
This commit is contained in:
199
imports/ui/util/GridTable.jsx
Normal file
199
imports/ui/util/GridTable.jsx
Normal file
@@ -0,0 +1,199 @@
|
||||
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import React, { useState } from 'react';
|
||||
import { useTracker } from 'meteor/react-meteor-data';
|
||||
import _ from 'lodash';
|
||||
|
||||
|
||||
|
||||
//{columns.map((column) => <td>{column.value(row)}</td>)}
|
||||
const WholeRow = ({row, columns}) => {
|
||||
return <tr><td>Test</td></tr>
|
||||
}
|
||||
|
||||
const ColumnHeader = ({column}) => {
|
||||
// console.log("Rendering column header")
|
||||
return <td>
|
||||
{column.isActions ?
|
||||
"TODO: Add widgets"
|
||||
:
|
||||
column.title
|
||||
}
|
||||
</td>
|
||||
}
|
||||
|
||||
const Row = ({columns, row, getRowKey, editedRowKey, editor, setEdited}) => {
|
||||
return <tr><td>Test</td></tr>
|
||||
}
|
||||
/*
|
||||
<tr>
|
||||
{!editedRowKey || getRowKey(row) !== editedRowKey ?
|
||||
columns.map((column, i) => <Cell column={column} row={row}/>)
|
||||
:
|
||||
editor
|
||||
}
|
||||
</tr>
|
||||
*/
|
||||
// onDoubleClick={(e) => {(!editedRowKey || getRowKey(row) !== editedRowKey) && setEdited(row)}}
|
||||
const Cell = ({row, column}) => {
|
||||
return <td>test</td>
|
||||
}
|
||||
/*
|
||||
<td>
|
||||
{column.isActions ?
|
||||
"TODO"
|
||||
:
|
||||
column.value(row)
|
||||
}
|
||||
</td>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Example:
|
||||
* import {useState} from 'react';
|
||||
* const[edited, setEdited] = useState(undefined);
|
||||
* <GridTable setEdited={setEdited} edited={edited} rows={rows} columns={columnns} actions={actions}>
|
||||
* <!-- Editor JSX here. -->
|
||||
* </GridTable>
|
||||
*
|
||||
* export let rows;
|
||||
export let columns;
|
||||
export let rowKey; //Must only be null/undefined if the row is a new object (not associated with a row in the table). Should not change.
|
||||
export let edited;
|
||||
export let actions;
|
||||
export let selection;
|
||||
* @param props
|
||||
* @returns {JSX.Element}
|
||||
*/
|
||||
export default ({columns, rows, actions, getRowKey, edited, setEdited, children}) => {
|
||||
// Setup a width for each column.
|
||||
columns.forEach(column => {
|
||||
let min = column.minWidth ? Math.max(10, column.minWidth) : 10;
|
||||
let weight = column.weight ? Math.max(1, column.weight) : 1;
|
||||
column.width = 'minmax(' + min + 'px, ' + weight + 'fr)';
|
||||
column.isActions = false;
|
||||
});
|
||||
|
||||
// Add the actions column to the end.
|
||||
// TODO: Allow it to be positioned.
|
||||
if(actions) {
|
||||
// TODO: make this fixed width based on the possible widget widths.
|
||||
actions.width = 'minmax(10px, 1fr)';
|
||||
actions.isActions = true;
|
||||
columns[columns.length] = actions;
|
||||
}
|
||||
|
||||
// Collect the column widths for the layout.
|
||||
let gridTemplateColumns = columns.map(({width}) => width).join(' ');
|
||||
|
||||
// Resize column code.
|
||||
let headerBeingResized = null;
|
||||
let horizontalScrollOffset = 0;
|
||||
const initResize = ({target}) => {
|
||||
headerBeingResized = target.parentNode;
|
||||
window.addEventListener('mousemove', onMouseMove);
|
||||
window.addEventListener('mouseup', completeResize);
|
||||
headerBeingResized.classList.add('header--being-resized');
|
||||
};
|
||||
const completeResize = () => {
|
||||
window.removeEventListener('mousemove', onMouseMove);
|
||||
window.removeEventListener('mouseup', completeResize);
|
||||
headerBeingResized.classList.remove('header--being-resized');
|
||||
headerBeingResized = null;
|
||||
};
|
||||
const onMouseMove = e => {
|
||||
try {
|
||||
// Calculate the desired width.
|
||||
horizontalScrollOffset = document.documentElement.scrollLeft;
|
||||
let parentX = Math.round(headerBeingResized.getBoundingClientRect().x);
|
||||
const width = horizontalScrollOffset + (e.clientX - parentX);
|
||||
// Update the column object with the new size value.
|
||||
const column = columns.find(({element}) => element === headerBeingResized);
|
||||
column.width = Math.max(column.minWidth, width) + "px";
|
||||
// Ensure all the column widths are converted to fixed sizes.
|
||||
columns.forEach((column, index) => {
|
||||
if((index < columns.length - 1) && (column.width.startsWith('minmax'))) {
|
||||
column.width = parseInt(column.element.clientWidth, 10) + 'px';
|
||||
}
|
||||
});
|
||||
// Render the new column sizes.
|
||||
gridTemplateColumns = columns.map(({width}) => width).join(' ');
|
||||
} catch(e) {console.log(e);}
|
||||
}
|
||||
|
||||
// Select row code.
|
||||
let selectedRowElement = null;
|
||||
const selectRow = (e, row) => {
|
||||
let element = e.target;
|
||||
|
||||
while(element && element.nodeName !== "TR") element = element.parentNode;
|
||||
|
||||
if(selectedRowElement) {
|
||||
selectedRowElement.classList.remove('selected');
|
||||
}
|
||||
|
||||
selectedRowElement = element;
|
||||
element.classList.add('selected');
|
||||
dispatch('selection', selectedRowElement.dataset.key);
|
||||
}
|
||||
|
||||
// Edit row code.
|
||||
let editorContainer;
|
||||
let editorTable;
|
||||
// Listen for changes to the edited variable. Move the editor row and display it when there is a value.
|
||||
// Relies on the table row being hidden when the edited value matches the row's value.
|
||||
useTracker(() => {
|
||||
if(editorContainer) {
|
||||
if(edited) {
|
||||
let id = rowKey($edited);
|
||||
let hiddenRow = editorTable.querySelector('tbody tr[data-key="' + id + '"]');
|
||||
|
||||
if(!hiddenRow) {
|
||||
let body = editorTable.querySelector('tbody');
|
||||
body.firstChild ? body.insertBefore(editorContainer, body.firstChild) : body.appendChild(editorContainer);
|
||||
editorContainer.classList.remove('hidden');
|
||||
}
|
||||
else {
|
||||
//let editor = hiddenRow.querySelector('.editor');
|
||||
let body = editorTable.querySelector('tbody');
|
||||
let next = hiddenRow.nextSibling;
|
||||
//editor.appendChild(editorContainer);
|
||||
next ? body.insertBefore(editorContainer, next) : body.appendChild(editorContainer);
|
||||
editorContainer.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log("Edited cleared");
|
||||
editorContainer.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let editedRowKey = edited ? getRowKey(edited) : undefined;
|
||||
console.log("Rendering grid table")
|
||||
|
||||
// let contents = "";
|
||||
//
|
||||
// for(let row of rows) {
|
||||
// contents += <WholeRow row={row} columns={columns}/>
|
||||
// // contents += <tr>
|
||||
// // for(let column of columns) {
|
||||
// // contents += <CellValue row={row} column={column}></CellValue>
|
||||
// // }
|
||||
// // contents += </tr>
|
||||
// }
|
||||
|
||||
return <div className={'grid-table-container'}>
|
||||
<table style={{gridTemplateColumns}}>
|
||||
<thead>
|
||||
<tr>
|
||||
{columns.map((column, i) => <ColumnHeader key={column.key} column={column}/>)}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{/*{rows.map((row, i) => <Row key={getRowKey(row)} row={row} columns={columns} getRowKey={getRowKey} editedRowKey={editedRowKey} editor={children} setEdited={setEdited}/>)}*/}
|
||||
{rows.map((row)=><WholeRow row={row} columns={columns}/>)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
Reference in New Issue
Block a user