Skip to content

Instantly share code, notes, and snippets.

@cmackenz
Last active March 21, 2018 10:12
Show Gist options
  • Save cmackenz/8e6acda61b3f9e712d6d9e8c005dd59d to your computer and use it in GitHub Desktop.
Save cmackenz/8e6acda61b3f9e712d6d9e8c005dd59d to your computer and use it in GitHub Desktop.
Ember Light Table Draggable Row Mixin
import Ember from 'ember';
const {
computed,
Mixin,
run,
} = Ember;
let sourceRow;
export default Mixin.create({
classNameBindings: ['isDragging', 'isDragTarget', 'dragDirection'],
attributeBindings: ['isDraggable:draggable', 'isDroppable:droppable'],
isDragging: false,
isDragTarget: false,
dragDirection: computed('isDragTarget', function () {
if (this.get('isDragTarget')) {
let rows = this.get('dragRowGroup');
let targetIdx = rows.indexOf(this.get('row'));
let sourceIdx = rows.indexOf(sourceRow);
let direction = (sourceIdx - targetIdx) < 0 ? 'down' : 'up';
return `drag-${direction}`;
}
}).readOnly(),
dragRowGroup: computed('row', function () {
return this.get('table.rows');
}).readOnly(),
isDropTarget: computed(function () {
return this.get('isDroppable');
}).volatile().readOnly(),
dragStart(e) {
this._super(...arguments);
let row = this.get('row');
e.dataTransfer.setData('text', row.get('rowId'));
e.dataTransfer.effectAllowed = 'move';
sourceRow = row;
this.set('isDragging', true);
this.sendAction('onRowDrag', sourceRow, ...arguments);
/*
NOTE: This is a fix for Firefox to prevent the click event
from being triggered after a drop.
*/
this.__click__ = this.click;
this.click = undefined;
},
dragEnter(e) {
this._super(...arguments);
if (this.get('isDropTarget')) {
e.preventDefault();
this.set('isDragTarget', this.get('row') !== sourceRow);
}
},
dragOver(e) {
this._super(...arguments);
if (this.get('isDropTarget')) {
e.preventDefault();
/*
NOTE: dragLeave will be triggered by any child elements inside the
row. This code ensures the row being dragged over continues to be
identified as the current drop target
*/
if (!this.get('isDragTarget')) {
this.set('isDragTarget', this.get('row') !== sourceRow);
}
}
},
dragLeave() {
this._super(...arguments);
this.set('isDragTarget', false);
},
dragEnd() {
this._super(...arguments);
this.setProperties({isDragTarget: false, isDragging: false});
/*
If sourceRow still references a row, it means that a successful drop did not happen.
*/
if (sourceRow) {
this.sendAction('onRowDrop', sourceRow, false, ...arguments);
sourceRow = null;
}
/*
Restore click event
*/
this._clickResetTimer = run.next(this, () => this.click = this.__click__);
},
drop(e) {
this._super(...arguments);
let targetRow = this.get('row');
let table = this.get('table');
let rows = this.get('dragRowGroup');
let _rows = rows.toArray();
let targetRowIdx = _rows.indexOf(targetRow);
e.dataTransfer.dropEffect = 'move';
e.preventDefault();
e.stopPropagation();
table.propertyWillChange('rows');
_rows.removeObject(sourceRow);
_rows.insertAt(targetRowIdx, sourceRow);
rows.setObjects(_rows);
table.propertyDidChange('rows');
this.setProperties({isDragTarget: false, isDragging: false});
this.get('onRowDropped')(sourceRow, targetRowIdx);
sourceRow = null;
},
destroy() {
this._super(...arguments);
run.cancel(this._clickResetTimer);
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment