@revolist/revogrid
Version:
Virtual reactive data grid spreadsheet component - RevoGrid.
174 lines (173 loc) • 7 kB
JavaScript
/*!
* Built by Revolist OU ❤️
*/
/**
* Plugin for column manual move
*/
import debounce from "lodash/debounce";
import each from "lodash/each";
import { getItemByPosition } from "../../store/index";
import { BasePlugin } from "../base.plugin";
import { ColumnOrderHandler } from "./order-column.handler";
import { dispatch } from "../dispatcher";
import { ON_COLUMN_CLICK } from "../../components/header/header-cell-renderer";
import { isColGrouping } from "../../utils/column.utils";
const COLUMN_CLICK = ON_COLUMN_CLICK;
const MOVE = 'columndragmousemove';
const DRAG_END = 'columndragend';
const BEFORE_DRAG_END = 'beforecolumndragend';
// use this event subscription to drop D&D for particular columns
const DRAG_START = 'columndragstart';
export class ColumnMovePlugin extends BasePlugin {
constructor(revogrid, providers) {
super(revogrid, providers);
this.revogrid = revogrid;
this.providers = providers;
this.moveFunc = debounce((e) => this.doMove(e), 5);
this.staticDragData = null;
this.dragData = null;
this.localSubscriptions = {};
this.orderUi = new ColumnOrderHandler();
revogrid.appendChild(this.orderUi.render());
revogrid.classList.add('column-draggable');
// Register events
this.localSubscriptions['mouseleave'] = {
target: document,
callback: (e) => this.onMouseOut(e),
};
this.localSubscriptions['mouseup'] = {
target: document,
callback: (e) => this.onMouseUp(e),
};
this.localSubscriptions['mousemove'] = {
target: document,
callback: (e) => this.move(e),
};
this.addEventListener(COLUMN_CLICK, ({ detail }) => this.dragStart(detail));
}
dragStart({ event, data }) {
if (event.defaultPrevented) {
return;
}
const { defaultPrevented } = dispatch(this.revogrid, DRAG_START, data);
// check if allowed to drag particulat column
if (defaultPrevented) {
return;
}
this.clearOrder();
const { mouseleave, mouseup, mousemove } = this.localSubscriptions;
mouseleave.target.addEventListener('mouseleave', mouseleave.callback);
mouseup.target.addEventListener('mouseup', mouseup.callback);
const dataEl = event.target.closest('revogr-header');
const scrollEl = event.target.closest('revogr-viewport-scroll');
if (!dataEl || !scrollEl) {
return;
}
// no grouping drag and no row header column drag
if (isColGrouping(data) || data.providers.type === 'rowHeaders') {
return;
}
const cols = this.getDimension(data.pin || 'rgCol');
const gridRect = this.revogrid.getBoundingClientRect();
const elRect = dataEl.getBoundingClientRect();
const startItem = getItemByPosition(cols, getLeftRelative(event.x, gridRect.left, elRect.left - gridRect.left));
this.staticDragData = {
startPos: event.x,
startItem,
data,
dataEl,
scrollEl,
gridEl: this.revogrid,
cols,
};
this.dragData = this.getData(this.staticDragData);
mousemove.target.addEventListener('mousemove', mousemove.callback);
this.orderUi.start(event, Object.assign(Object.assign({}, this.dragData), this.staticDragData));
}
doMove(e) {
if (!this.staticDragData) {
return;
}
const dragData = (this.dragData = this.getData(this.staticDragData));
if (!dragData) {
return;
}
const start = this.staticDragData.startPos;
if (Math.abs(start - e.x) > 10) {
const x = getLeftRelative(e.x, this.dragData.gridRect.left, this.dragData.scrollOffset);
const rgCol = getItemByPosition(this.staticDragData.cols, x);
this.orderUi.autoscroll(x, dragData.elRect.width);
// prevent position change if out of bounds
if (rgCol.itemIndex >= this.staticDragData.cols.count) {
return;
}
this.orderUi.showHandler(rgCol.end + dragData.scrollOffset, dragData.gridRect.width);
}
}
move(e) {
dispatch(this.revogrid, MOVE, e);
// then do move
this.moveFunc(e);
}
onMouseOut(_) {
this.clearOrder();
}
onMouseUp(e) {
// apply new positions
if (this.dragData && this.staticDragData) {
let relativePos = getLeftRelative(e.x, this.dragData.gridRect.left, this.dragData.scrollOffset);
if (relativePos < 0) {
relativePos = 0;
}
const newPosition = getItemByPosition(this.staticDragData.cols, relativePos);
const store = this.providers.column.stores[this.dragData.type].store;
const newItems = [...store.get('items')];
// prevent position change if needed
const { defaultPrevented: stopDrag } = dispatch(this.revogrid, BEFORE_DRAG_END, Object.assign(Object.assign({}, this.staticDragData), { startPosition: this.staticDragData.startItem, newPosition, newItem: store.get('source')[newItems[this.staticDragData.startItem.itemIndex]] }));
if (!stopDrag) {
const prevItems = [...newItems];
// todo: if move item out of group remove item from group
const toMove = newItems.splice(this.staticDragData.startItem.itemIndex, 1);
newItems.splice(newPosition.itemIndex, 0, ...toMove);
store.set('items', newItems);
this.providers.dimension.updateSizesPositionByNewDataIndexes(this.dragData.type, newItems, prevItems);
}
dispatch(this.revogrid, DRAG_END, this.dragData);
}
this.clearOrder();
}
clearLocalSubscriptions() {
each(this.localSubscriptions, ({ target, callback }, key) => target.removeEventListener(key, callback));
}
clearOrder() {
this.staticDragData = null;
this.dragData = null;
this.clearLocalSubscriptions();
this.orderUi.stop(this.revogrid);
}
/**
* Clearing subscription
*/
clearSubscriptions() {
super.clearSubscriptions();
this.clearLocalSubscriptions();
}
getData({ gridEl, dataEl, data, }) {
const gridRect = gridEl.getBoundingClientRect();
const elRect = dataEl.getBoundingClientRect();
const scrollOffset = elRect.left - gridRect.left;
return {
elRect,
gridRect,
type: data.pin || 'rgCol',
scrollOffset,
};
}
getDimension(type) {
return this.providers.dimension.stores[type].getCurrentState();
}
}
export function getLeftRelative(absoluteX, gridPos, offset) {
return absoluteX - gridPos - offset;
}
//# sourceMappingURL=column.drag.plugin.js.map