UNPKG

keystone

Version:

Web Application Framework and Admin GUI / Content Management System built on Express.js and Mongoose

161 lines (140 loc) 5.06 kB
import React from 'react'; import classnames from 'classnames'; import ListControl from '../ListControl'; import { Columns } from 'FieldTypes'; import { DropTarget, DragSource } from 'react-dnd'; import { setDragBase, resetItems, reorderItems, setRowAlert, moveItem, } from '../../actions'; const ItemsRow = React.createClass({ propTypes: { columns: React.PropTypes.array, id: React.PropTypes.any, index: React.PropTypes.number, items: React.PropTypes.object, list: React.PropTypes.object, // Injected by React DnD: isDragging: React.PropTypes.bool, // eslint-disable-line react/sort-prop-types connectDragSource: React.PropTypes.func, // eslint-disable-line react/sort-prop-types connectDropTarget: React.PropTypes.func, // eslint-disable-line react/sort-prop-types connectDragPreview: React.PropTypes.func, // eslint-disable-line react/sort-prop-types }, renderRow (item) { const itemId = item.id; const rowClassname = classnames({ 'ItemList__row--dragging': this.props.isDragging, 'ItemList__row--selected': this.props.checkedItems[itemId], 'ItemList__row--manage': this.props.manageMode, 'ItemList__row--success': this.props.rowAlert.success === itemId, 'ItemList__row--failure': this.props.rowAlert.fail === itemId, }); // item fields var cells = this.props.columns.map((col, i) => { var ColumnType = Columns[col.type] || Columns.__unrecognised__; var linkTo = !i ? `${Keystone.adminPath}/${this.props.list.path}/${itemId}` : undefined; return <ColumnType key={col.path} list={this.props.list} col={col} data={item} linkTo={linkTo} />; }); // add sortable icon when applicable if (this.props.list.sortable) { cells.unshift(<ListControl key="_sort" type="sortable" dragSource={this.props.connectDragSource} />); } // add delete/check icon when applicable if (!this.props.list.nodelete) { cells.unshift(this.props.manageMode ? ( <ListControl key="_check" type="check" active={this.props.checkedItems[itemId]} /> ) : ( <ListControl key="_delete" onClick={(e) => this.props.deleteTableItem(item, e)} type="delete" /> )); } var addRow = (<tr key={'i' + item.id} onClick={this.props.manageMode ? (e) => this.props.checkTableItem(item, e) : null} className={rowClassname}>{cells}</tr>); if (this.props.list.sortable) { return ( // we could add a preview container/image // this.props.connectDragPreview(this.props.connectDropTarget(addRow)) this.props.connectDropTarget(addRow) ); } else { return (addRow); } }, render () { return this.renderRow(this.props.item); }, }); module.exports = exports = ItemsRow; // Expose Sortable /** * Implements drag source. */ const dragItem = { beginDrag (props) { const send = { ...props }; props.dispatch(setDragBase(props.item, props.index)); return { ...send }; }, endDrag (props, monitor, component) { if (!monitor.didDrop()) { props.dispatch(resetItems(props.id)); return; } const page = props.currentPage; const pageSize = props.pageSize; // If we were dropped onto a page change target, then droppedOn.prevSortOrder etc will be // set by that target, and we should use those values. If we were just dropped onto a new row // then we need to calculate these values ourselves. const droppedOn = monitor.getDropResult(); const prevSortOrder = droppedOn.prevSortOrder || props.sortOrder; // To explain the following line, suppose we are on page 3 and there are 10 items per page. // Previous to this page, there are (3 - 1)*10 = 20 items before us. If we have index 6 // on this page, then we're the 7th item to display (index starts from 0), and so we // want to update the display order to 20 + 7 = 27. const newSortOrder = droppedOn.newSortOrder || (page - 1) * pageSize + droppedOn.index + 1; // If we were dropped on a page change target, then droppedOn.gotToPage will be set, and we should // pass this to reorderItems, which will then change the page for the user. props.dispatch(reorderItems(props.item, prevSortOrder, newSortOrder, Number(droppedOn.goToPage))); }, }; /** * Implements drag target. */ const dropItem = { drop (props, monitor, component) { return { ...props }; }, hover (props, monitor, component) { // reset row alerts if (props.rowAlert.success || props.rowAlert.fail) { props.dispatch(setRowAlert({ reset: true, })); } const dragged = monitor.getItem().index; const over = props.index; // self if (dragged === over) { return; } props.dispatch(moveItem(dragged, over, props)); monitor.getItem().index = over; }, }; /** * Specifies the props to inject into your component. */ function dragProps (connect, monitor) { return { connectDragSource: connect.dragSource(), isDragging: monitor.isDragging(), connectDragPreview: connect.dragPreview(), }; } function dropProps (connect) { return { connectDropTarget: connect.dropTarget(), }; }; exports.Sortable = DragSource('item', dragItem, dragProps)(DropTarget('item', dropItem, dropProps)(ItemsRow));