11import Component from '@glimmer/component' ;
22import Sortable from 'sortablejs' ;
3- import { bind , scheduleOnce } from '@ember/runloop' ;
3+ import { bind , next } from '@ember/runloop' ;
44import { action } from '@ember/object' ;
5- import { next } from '@ember/runloop' ;
65import { tracked } from '@glimmer/tracking' ;
76import { move , insertAt , removeFrom } from 'ember-sortablejs/utils/array-utils' ;
87import { inject as service } from '@ember/service' ;
@@ -12,9 +11,11 @@ export default class SortableJsComponent extends Component {
1211
1312 @tracked list = [ ] ;
1413
14+ cachedList = null ;
15+ hasUpdatedList = false ; // Used to prevent unwanted renders. Probably there's a better way to do this.
1516 #sortableContainer = null ;
16- # sortableInstance = null ;
17- # internalEvents = [
17+ sortableInstance = null ;
18+ internalEvents = [
1819 'onStart' ,
1920 'onAdd' ,
2021 'onUpdate' ,
@@ -66,7 +67,7 @@ export default class SortableJsComponent extends Component {
6667 this . #sortableContainer = element ;
6768
6869 next ( this , ( ) => {
69- this . # sortableInstance = Sortable . create ( element , options ) ;
70+ this . sortableInstance = Sortable . create ( element , options ) ;
7071 this . setupEventHandlers ( ) ;
7172 this . setupInternalEventHandlers ( ) ;
7273 this . setList ( ) ;
@@ -78,8 +79,19 @@ export default class SortableJsComponent extends Component {
7879 this . list = [ ...( this . args . items || [ ] ) ] ;
7980 }
8081
82+ @action
83+ cancelDnD ( ) {
84+ if ( this . cachedList ) {
85+ this . list = [ ...this . cachedList ] ;
86+ this . cachedList = null ;
87+ this . dragStore . dragAddInstance ?. cancelDnD ( ) ;
88+ }
89+ this . dragStore . reset ( ) ;
90+ }
91+
8192 willDestroy ( ) {
82- this . #sortableInstance. destroy ( ) ;
93+ this . sortableInstance . destroy ( ) ;
94+ this . dragStore . reset ( ) ;
8395 }
8496
8597 onUpdate ( evt ) {
@@ -88,7 +100,8 @@ export default class SortableJsComponent extends Component {
88100 oldDraggableIndex,
89101 } = evt ;
90102
91- this . list = move ( this . list , oldDraggableIndex , newDraggableIndex ) ;
103+ this . sync ( evt . item , move ( this . list , oldDraggableIndex , newDraggableIndex ) ) ;
104+ this . hasUpdatedList = true ;
92105 this . args ?. onUpdate ?. ( evt ) ;
93106 }
94107
@@ -98,57 +111,66 @@ export default class SortableJsComponent extends Component {
98111 } = evt ;
99112
100113 if ( evt . pullMode !== 'clone' ) {
101- this . list = removeFrom ( this . list , oldDraggableIndex ) ;
114+ this . sync ( evt . item , removeFrom ( this . list , oldDraggableIndex ) ) ;
115+ this . hasUpdatedList = true ;
102116 }
103117
104118 this . args ?. onRemove ?. ( evt ) ;
105119 }
106120
107121 onAdd ( evt ) {
108- evt . item . remove ( ) ; // without this DOM is wrong
122+ this . cachedList = [ ...this . list ] ;
123+ this . dragStore . dragAddInstance = this ;
109124 const {
110125 oldDraggableIndex,
111126 newDraggableIndex,
112127 } = evt ;
113- const oldItem = this . dragStore . dragging . list [ oldDraggableIndex ] ;
114- this . list = insertAt ( this . list , newDraggableIndex , oldItem )
128+ const oldItem = this . dragStore . dragStartInstance . list [ oldDraggableIndex ] ;
129+
130+ this . sync ( evt . item , insertAt ( this . list , newDraggableIndex , oldItem ) ) ;
115131 this . args ?. onAdd ?. ( evt ) ;
116132 }
117133
118134 onStart ( evt ) {
119- this . dragStore . dragging = this ;
135+ this . cachedList = [ ...this . list ] ;
136+ this . dragStore . dragStartInstance = this ;
120137 this . args ?. onStart ?. ( evt ) ;
121138 }
122139
123- onEnd ( evt ) {
124- this . args ?. onEnd ?. ( evt ) ;
125- this . dragStore . dragging = null ;
140+ onEnd ( evt , ) {
141+ if ( ! this . hasUpdatedList ) {
142+ this . sync ( evt . item , this . list ) ;
143+ }
144+
145+ this . args ?. onEnd ?. ( evt , this . cancelDnD ) ;
146+ this . hasUpdatedList = false ;
147+ }
148+
149+ sync ( element , changedArray ) {
150+ element . remove ( ) ;
151+ this . list = [ ...changedArray ] ;
126152 }
127153
128154 setupEventHandlers ( ) {
129155 this . #events. forEach ( eventName => {
130156 const action = this . args [ eventName ] ;
131157 if ( typeof action === 'function' ) {
132- this . # sortableInstance. option ( eventName , bind ( this , 'performExternalAction' , eventName ) ) ;
158+ this . sortableInstance . option ( eventName , bind ( this , 'performExternalAction' , eventName ) ) ;
133159 }
134160 } ) ;
135161 }
136162
137163 setupInternalEventHandlers ( ) {
138- this . # internalEvents. forEach ( eventName => {
139- this . # sortableInstance. option ( eventName , bind ( this , this [ eventName ] ) ) ;
164+ this . internalEvents . forEach ( eventName => {
165+ this . sortableInstance . option ( eventName , bind ( this , this [ eventName ] ) ) ;
140166 } ) ;
141167 }
142168
143169 performExternalAction ( actionName , ...args ) {
144- let action = this . args [ actionName ] ;
145-
146- if ( typeof action === 'function' ) {
147- action ( ...args , this . sortable ) ;
148- }
170+ this . args [ actionName ] ?. ( ...args )
149171 }
150172
151173 setOption ( option , value ) {
152- this . # sortableInstance. option ( option , value ) ;
174+ this . sortableInstance . option ( option , value ) ;
153175 }
154176}
0 commit comments