Last active
March 21, 2018 10:12
-
-
Save cmackenz/8e6acda61b3f9e712d6d9e8c005dd59d to your computer and use it in GitHub Desktop.
Ember Light Table Draggable Row Mixin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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