1
1
import Component from '@glimmer/component' ;
2
2
import Sortable from 'sortablejs' ;
3
- import { bind } from '@ember/runloop' ;
3
+ import { bind , scheduleOnce } from '@ember/runloop' ;
4
4
import { action } from '@ember/object' ;
5
+ import { next } from '@ember/runloop' ;
6
+ import { tracked } from '@glimmer/tracking' ;
7
+ import { move , insertAt , removeFrom } from 'ember-sortablejs/utils/array-utils' ;
8
+ import { inject as service } from '@ember/service' ;
5
9
6
10
export default class SortableJsComponent extends Component {
7
- sortable = null ;
11
+ @service dragStore ;
12
+ @tracked list = [ ] ;
8
13
9
- #events = [
10
- 'onChoose' ,
11
- 'onUnchoose' ,
14
+ #sortableContainer = null ;
15
+ #sortableInstance = null ;
16
+ #internalEvents = [
12
17
'onStart' ,
13
- 'onEnd' ,
14
18
'onAdd' ,
15
19
'onUpdate' ,
16
- 'onSort' ,
17
20
'onRemove' ,
21
+ 'onEnd' ,
22
+ ] ;
23
+ #events = [
18
24
'onMove' ,
19
- 'onClone' ,
20
25
'onChange' ,
26
+ 'onChoose' ,
27
+ 'onUnchoose' ,
28
+ 'onSort' ,
29
+ 'onClone' ,
21
30
'scrollFn' ,
22
31
'setData' ,
23
32
'onFilter' ,
24
33
'onSpill' ,
25
34
] ;
26
35
36
+ get element ( ) {
37
+ return this . args . tag || 'div' ;
38
+ }
39
+
40
+ get internalList ( ) {
41
+ // fix identity diffing
42
+ return this . list . map ( ( item , i ) => ( { id : i += 1 , item } ) )
43
+ }
44
+
27
45
@action
28
46
setOptions ( ) {
29
47
for ( let [ key , value ] of Object . entries ( this . args . options ) ) {
@@ -40,23 +58,75 @@ export default class SortableJsComponent extends Component {
40
58
const defaults = { } ;
41
59
const options = Object . assign ( { } , defaults , this . args . options ) ;
42
60
43
- this . sortable = Sortable . create ( element , options ) ;
44
- this . setupEventHandlers ( ) ;
61
+ this . #sortableContainer = element ;
62
+
63
+ next ( this , ( ) => {
64
+ this . #sortableInstance = Sortable . create ( element , options ) ;
65
+ this . list = [ ...( this . args . items || [ ] ) ] ;
66
+ this . setupEventHandlers ( ) ;
67
+ this . setupInternalEventHandlers ( ) ;
68
+ } ) ;
45
69
}
46
70
47
71
willDestroy ( ) {
48
- this . sortable . destroy ( ) ;
72
+ this . #sortableInstance. destroy ( ) ;
73
+ }
74
+
75
+ onUpdate ( evt ) {
76
+ const {
77
+ oldDraggableIndex,
78
+ newDraggableIndex,
79
+ } = evt ;
80
+
81
+ this . list = move ( this . list , oldDraggableIndex , newDraggableIndex ) ;
82
+ this . args ?. onUpdate ?. ( evt ) ;
83
+ }
84
+
85
+ onRemove ( evt ) {
86
+ const {
87
+ oldDraggableIndex,
88
+ } = evt ;
89
+
90
+ this . list = removeFrom ( this . list , oldDraggableIndex ) ;
91
+ this . args ?. onRemove ?. ( evt ) ;
92
+ }
93
+
94
+ onAdd ( evt ) {
95
+ // evt.item.remove(); // without this DOM is wrong
96
+ const {
97
+ oldDraggableIndex,
98
+ newDraggableIndex,
99
+ } = evt ;
100
+ const oldItem = this . dragStore . dragging . list [ oldDraggableIndex ] ;
101
+ this . list = insertAt ( this . list , newDraggableIndex , oldItem )
102
+ this . args ?. onAdd ?. ( evt ) ;
103
+ }
104
+
105
+ onStart ( evt ) {
106
+ this . dragStore . dragging = this ;
107
+ this . args ?. onStart ?. ( evt ) ;
108
+ }
109
+
110
+ onEnd ( evt ) {
111
+ this . args ?. onEnd ?. ( evt ) ;
112
+ this . dragStore . dragging = null ;
49
113
}
50
114
51
115
setupEventHandlers ( ) {
52
116
this . #events. forEach ( eventName => {
53
117
const action = this . args [ eventName ] ;
54
118
if ( typeof action === 'function' ) {
55
- this . sortable . option ( eventName , bind ( this , 'performExternalAction' , eventName ) ) ;
119
+ this . #sortableInstance . option ( eventName , bind ( this , 'performExternalAction' , eventName ) ) ;
56
120
}
57
121
} ) ;
58
122
}
59
123
124
+ setupInternalEventHandlers ( ) {
125
+ this . #internalEvents. forEach ( eventName => {
126
+ this . #sortableInstance. option ( eventName , bind ( this , this [ eventName ] ) ) ;
127
+ } ) ;
128
+ }
129
+
60
130
performExternalAction ( actionName , ...args ) {
61
131
let action = this . args [ actionName ] ;
62
132
@@ -66,6 +136,6 @@ export default class SortableJsComponent extends Component {
66
136
}
67
137
68
138
setOption ( option , value ) {
69
- this . sortable . option ( option , value ) ;
139
+ this . #sortableInstance . option ( option , value ) ;
70
140
}
71
141
}
0 commit comments