6
6
angular . module ( 'ui.sortable' , [ ] )
7
7
. value ( 'uiSortableConfig' , { } )
8
8
. directive ( 'uiSortable' , [
9
- 'uiSortableConfig' , '$timeout' , '$ log',
10
- function ( uiSortableConfig , $timeout , $ log) {
9
+ 'uiSortableConfig' , '$log' ,
10
+ function ( uiSortableConfig , log ) {
11
11
return {
12
12
require : '?ngModel' ,
13
13
link : function ( scope , element , attrs , ngModel ) {
14
- var savedNodes ;
15
14
16
15
function combineCallbacks ( first , second ) {
17
- if ( second && ( typeof second === "function" ) ) {
18
- return function ( e , ui ) {
19
- first ( e , ui ) ;
20
- second ( e , ui ) ;
16
+ if ( second && ( typeof second === "function" ) ) {
17
+ return function ( e , ui ) {
18
+ first ( e , ui ) ;
19
+ second ( e , ui ) ;
21
20
} ;
22
21
}
23
22
return first ;
@@ -33,129 +32,87 @@ angular.module('ui.sortable', [])
33
32
update :null
34
33
} ;
35
34
35
+ var apply = function ( e , ui ) {
36
+ if ( ui . item . sortable . resort || ui . item . sortable . relocate ) {
37
+ scope . $apply ( ) ;
38
+ }
39
+ } ;
40
+
36
41
angular . extend ( opts , uiSortableConfig ) ;
37
42
38
43
if ( ngModel ) {
39
44
40
- // When we add or remove elements, we need the sortable to 'refresh'
41
- // so it can find the new/removed elements.
42
- scope . $watch ( attrs . ngModel + '.length' , function ( ) {
43
- // Timeout to let ng-repeat modify the DOM
44
- $timeout ( function ( ) {
45
- element . sortable ( "refresh" ) ;
46
- } ) ;
47
- } ) ;
45
+ ngModel . $render = function ( ) {
46
+ element . sortable ( "refresh" ) ;
47
+ } ;
48
48
49
49
callbacks . start = function ( e , ui ) {
50
- // Save the starting position of dragged item
50
+ // Save position of dragged item
51
51
ui . item . sortable = { index : ui . item . index ( ) } ;
52
52
} ;
53
53
54
- callbacks . activate = function ( e , ui ) {
55
- // We need to make a copy of the current element's contents so
56
- // we can restore it after sortable has messed it up.
57
- // This is inside activate (instead of start) in order to save
58
- // both lists when dragging between connected lists.
59
- savedNodes = element . contents ( ) ;
60
-
61
- // If this list has a placeholder (the connected lists won't),
62
- // don't inlcude it in saved nodes.
63
- var placeholder = element . sortable ( 'option' , 'placeholder' ) ;
64
-
65
- // placeholder.element will be a function if the placeholder, has
66
- // been created (placeholder will be an object). If it hasn't
67
- // been created, either placeholder will be false if no
68
- // placeholder class was given or placeholder.element will be
69
- // undefined if a class was given (placeholder will be a string)
70
- if ( placeholder && placeholder . element ) {
71
- savedNodes = savedNodes . not ( element . find (
72
- "." + placeholder . element ( )
73
- . attr ( 'class' ) . split ( / \s + / ) . join ( '.' ) ) ) ;
74
- }
54
+ callbacks . update = function ( e , ui ) {
55
+ // For some reason the reference to ngModel in stop() is wrong
56
+ ui . item . sortable . resort = ngModel ;
75
57
} ;
76
58
77
- callbacks . update = function ( e , ui ) {
78
- // Save current drop position but only if this is not a second
79
- // update that happens when moving between lists because then
80
- // the value will be overwritten with the old value
81
- if ( ! ui . item . sortable . received ) {
82
- ui . item . sortable . dropindex = ui . item . index ( ) ;
83
-
84
- // Cancel the sort (let ng-repeat do the sort for us)
85
- // Don't cancel if this is the received list because it has
86
- // already been canceled in the other list, and trying to cancel
87
- // here will mess up the DOM.
88
- element . sortable ( 'cancel' ) ;
89
- }
59
+ callbacks . receive = function ( e , ui ) {
60
+ ui . item . sortable . relocate = true ;
61
+ // added item to array into correct position and set up flag
62
+ ngModel . $modelValue . splice ( ui . item . index ( ) , 0 , ui . item . sortable . moved ) ;
63
+ } ;
90
64
91
- // Put the nodes back exactly the way they started (this is very
92
- // important because ng-repeat uses comment elements to delineate
93
- // the start and stop of repeat sections and sortable doesn't
94
- // respect their order (even if we cancel, the order of the
95
- // comments are still messed up).
96
- savedNodes . detach ( ) . appendTo ( element ) ;
97
-
98
- // If received is true (an item was dropped in from another list)
99
- // then we add the new item to this list otherwise wait until the
100
- // stop event where we will know if it was a sort or item was
101
- // moved here from another list
102
- if ( ui . item . sortable . received ) {
103
- scope . $apply ( function ( ) {
104
- ngModel . $modelValue . splice ( ui . item . sortable . dropindex , 0 ,
105
- ui . item . sortable . moved ) ;
106
- } ) ;
65
+ callbacks . remove = function ( e , ui ) {
66
+ // copy data into item
67
+ if ( ngModel . $modelValue . length === 1 ) {
68
+ ui . item . sortable . moved = ngModel . $modelValue . splice ( 0 , 1 ) [ 0 ] ;
69
+ } else {
70
+ ui . item . sortable . moved = ngModel . $modelValue . splice ( ui . item . sortable . index , 1 ) [ 0 ] ;
107
71
}
108
72
} ;
109
73
110
74
callbacks . stop = function ( e , ui ) {
111
- // If the received flag hasn't be set on the item, this is a
112
- // normal sort, if dropindex is set, the item was moved, so move
113
- // the items in the list.
114
- if ( ! ui . item . sortable . received && ( 'dropindex' in ui . item . sortable ) ) {
115
- scope . $apply ( function ( ) {
116
- ngModel . $modelValue . splice (
117
- ui . item . sortable . dropindex , 0 ,
118
- ngModel . $modelValue . splice ( ui . item . sortable . index , 1 ) [ 0 ] ) ;
119
- } ) ;
75
+ // digest all prepared changes
76
+ if ( ui . item . sortable . resort && ! ui . item . sortable . relocate ) {
77
+
78
+ // Fetch saved and current position of dropped element
79
+ var end , start ;
80
+ start = ui . item . sortable . index ;
81
+ end = ui . item . index ( ) ;
82
+
83
+ // Reorder array and apply change to scope
84
+ ui . item . sortable . resort . $modelValue . splice ( end , 0 , ui . item . sortable . resort . $modelValue . splice ( start , 1 ) [ 0 ] ) ;
85
+
120
86
}
121
87
} ;
122
88
123
- callbacks . receive = function ( e , ui ) {
124
- // An item was dropped here from another list, set a flag on the
125
- // item.
126
- ui . item . sortable . received = true ;
127
- } ;
89
+ scope . $watch ( attrs . uiSortable , function ( newVal , oldVal ) {
90
+ angular . forEach ( newVal , function ( value , key ) {
128
91
129
- callbacks . remove = function ( e , ui ) {
130
- // Remove the item from this list's model and copy data into item,
131
- // so the next list can retrive it
132
- scope . $apply ( function ( ) {
133
- ui . item . sortable . moved = ngModel . $modelValue . splice (
134
- ui . item . sortable . index , 1 ) [ 0 ] ;
135
- } ) ;
136
- } ;
92
+ if ( callbacks [ key ] ) {
93
+ // wrap the callback
94
+ value = combineCallbacks ( callbacks [ key ] , value ) ;
137
95
138
- scope . $watch ( attrs . uiSortable , function ( newVal , oldVal ) {
139
- angular . forEach ( newVal , function ( value , key ) {
140
- if ( callbacks [ key ] ) {
141
- if ( key === 'stop' ) {
96
+ if ( key === 'stop' ) {
142
97
// call apply after stop
143
- value = combineCallbacks (
144
- value , function ( ) { scope . $apply ( ) ; } ) ;
98
+ value = combineCallbacks ( value , apply ) ;
145
99
}
146
- // wrap the callback
147
- value = combineCallbacks ( callbacks [ key ] , value ) ;
148
100
}
101
+
149
102
element . sortable ( 'option' , key , value ) ;
150
103
} ) ;
151
104
} , true ) ;
152
105
153
- angular . forEach ( callbacks , function ( value , key ) {
106
+ angular . forEach ( callbacks , function ( value , key ) {
107
+
154
108
opts [ key ] = combineCallbacks ( value , opts [ key ] ) ;
155
109
} ) ;
156
110
111
+ // call apply after stop
112
+ opts . stop = combineCallbacks ( opts . stop , apply ) ;
113
+
157
114
} else {
158
- $ log. info ( 'ui.sortable: ngModel not provided!' , element ) ;
115
+ log . info ( 'ui.sortable: ngModel not provided!' , element ) ;
159
116
}
160
117
161
118
// Create sortable
0 commit comments