]> git.proxmox.com Git - extjs.git/blame - extjs/modern/modern/src/Sortable.js
add extjs 6.0.1 sources
[extjs.git] / extjs / modern / modern / src / Sortable.js
CommitLineData
6527f429
DM
1/**\r
2 * A mixin which allows a data component to be sorted\r
3 * @ignore\r
4 */\r
5Ext.define('Ext.Sortable', {\r
6 mixins: {\r
7 observable: 'Ext.mixin.Observable'\r
8 },\r
9\r
10 requires: ['Ext.util.Draggable'],\r
11\r
12 config: {\r
13 /**\r
14 * @cfg\r
15 * @inheritdoc\r
16 */\r
17 baseCls: Ext.baseCSSPrefix + 'sortable',\r
18\r
19 /**\r
20 * @cfg {Number} delay\r
21 * How many milliseconds a user must hold the draggable before starting a\r
22 * drag operation.\r
23 * @private\r
24 * @accessor\r
25 */\r
26 delay: 0\r
27\r
28 },\r
29\r
30 /**\r
31 * @cfg {String} direction\r
32 * Possible values: 'vertical', 'horizontal'.\r
33 */\r
34 direction: 'vertical',\r
35\r
36 /**\r
37 * @cfg {String} cancelSelector\r
38 * A simple CSS selector that represents elements within the draggable\r
39 * that should NOT initiate a drag.\r
40 */\r
41 cancelSelector: null,\r
42\r
43 // not yet implemented\r
44 //indicator: true,\r
45 //proxy: true,\r
46 //tolerance: null,\r
47\r
48 /**\r
49 * @cfg {HTMLElement/Boolean} constrain\r
50 * An Element to constrain the Sortable dragging to.\r
51 * If `true` is specified, the dragging will be constrained to the element\r
52 * of the sortable.\r
53 */\r
54 constrain: window,\r
55 /**\r
56 * @cfg {String} group\r
57 * Draggable and Droppable objects can participate in a group which are\r
58 * capable of interacting.\r
59 */\r
60 group: 'base',\r
61\r
62 /**\r
63 * @cfg {Boolean} revert\r
64 * This should NOT be changed.\r
65 * @private\r
66 */\r
67 revert: true,\r
68\r
69 /**\r
70 * @cfg {String} itemSelector\r
71 * A simple CSS selector that represents individual items within the Sortable.\r
72 */\r
73 itemSelector: null,\r
74\r
75 /**\r
76 * @cfg {String} handleSelector\r
77 * A simple CSS selector to indicate what is the handle to drag the Sortable.\r
78 */\r
79 handleSelector: null,\r
80\r
81 /**\r
82 * @cfg {Boolean} disabled\r
83 * Passing in `true` will disable this Sortable.\r
84 */\r
85 disabled: false,\r
86\r
87 // Properties\r
88\r
89 /**\r
90 * Read-only property that indicates whether a Sortable is currently sorting.\r
91 * @type Boolean\r
92 * @private\r
93 * @readonly\r
94 */\r
95 sorting: false,\r
96\r
97 /**\r
98 * Read-only value representing whether the Draggable can be moved vertically.\r
99 * This is automatically calculated by Draggable by the direction configuration.\r
100 * @type Boolean\r
101 * @private\r
102 * @readonly\r
103 */\r
104 vertical: false,\r
105\r
106 /**\r
107 * Creates new Sortable.\r
108 * @param {Mixed} el\r
109 * @param {Object} config\r
110 */\r
111 constructor : function(el, config) {\r
112 config = config || {};\r
113 Ext.apply(this, config);\r
114\r
115 this.addEvents(\r
116 /**\r
117 * @event sortstart\r
118 * @param {Ext.Sortable} this\r
119 * @param {Ext.event.Event} e\r
120 */\r
121 'sortstart',\r
122 /**\r
123 * @event sortend\r
124 * @param {Ext.Sortable} this\r
125 * @param {Ext.event.Event} e\r
126 */\r
127 'sortend',\r
128 /**\r
129 * @event sortchange\r
130 * @param {Ext.Sortable} this\r
131 * @param {Ext.Element} el The Element being dragged.\r
132 * @param {Number} index The index of the element after the sort change.\r
133 */\r
134 'sortchange'\r
135\r
136 // not yet implemented.\r
137 // 'sortupdate',\r
138 // 'sortreceive',\r
139 // 'sortremove',\r
140 // 'sortenter',\r
141 // 'sortleave',\r
142 // 'sortactivate',\r
143 // 'sortdeactivate'\r
144 );\r
145\r
146 this.el = Ext.get(el);\r
147 this.callParent();\r
148\r
149 this.mixins.observable.constructor.call(this);\r
150\r
151 if (this.direction == 'horizontal') {\r
152 this.horizontal = true;\r
153 }\r
154 else if (this.direction == 'vertical') {\r
155 this.vertical = true;\r
156 }\r
157 else {\r
158 this.horizontal = this.vertical = true;\r
159 }\r
160\r
161 this.el.addCls(this.baseCls);\r
162 this.startEventName = (this.getDelay() > 0) ? 'taphold' : 'tapstart';\r
163 if (!this.disabled) {\r
164 this.enable();\r
165 }\r
166 },\r
167\r
168 /**\r
169 * @private\r
170 */\r
171 onStart : function(e, t) {\r
172 if (this.cancelSelector && e.getTarget(this.cancelSelector)) {\r
173 return;\r
174 }\r
175 if (this.handleSelector && !e.getTarget(this.handleSelector)) {\r
176 return;\r
177 }\r
178\r
179 if (!this.sorting) {\r
180 this.onSortStart(e, t);\r
181 }\r
182 },\r
183\r
184 /**\r
185 * @private\r
186 */\r
187 onSortStart : function(e, t) {\r
188 this.sorting = true;\r
189 var draggable = Ext.create('Ext.util.Draggable', t, {\r
190 threshold: 0,\r
191 revert: this.revert,\r
192 direction: this.direction,\r
193 constrain: this.constrain === true ? this.el : this.constrain,\r
194 animationDuration: 100\r
195 });\r
196 draggable.on({\r
197 drag: this.onDrag,\r
198 dragend: this.onDragEnd,\r
199 scope: this\r
200 });\r
201\r
202 this.dragEl = t;\r
203 this.calculateBoxes();\r
204\r
205 if (!draggable.dragging) {\r
206 draggable.onStart(e);\r
207 }\r
208\r
209 this.fireEvent('sortstart', this, e);\r
210 },\r
211\r
212 /**\r
213 * @private\r
214 */\r
215 calculateBoxes : function() {\r
216 this.items = [];\r
217 var els = this.el.select(this.itemSelector, false),\r
218 ln = els.length, i, item, el, box;\r
219\r
220 for (i = 0; i < ln; i++) {\r
221 el = els[i];\r
222 if (el != this.dragEl) {\r
223 item = Ext.fly(el).getRegion();\r
224 item.el = el;\r
225 this.items.push(item);\r
226 }\r
227 }\r
228 },\r
229\r
230 /**\r
231 * @private\r
232 */\r
233 onDrag : function(draggable, e) {\r
234 var items = this.items,\r
235 ln = items.length,\r
236 region = draggable.region,\r
237 sortChange = false,\r
238 i, intersect, overlap, item;\r
239\r
240 for (i = 0; i < ln; i++) {\r
241 item = items[i];\r
242 intersect = region.intersect(item);\r
243 if (intersect) {\r
244 if (this.vertical && Math.abs(intersect.top - intersect.bottom) > (region.bottom - region.top) / 2) {\r
245 if (region.bottom > item.top && item.top > region.top) {\r
246 draggable.el.insertAfter(item.el);\r
247 }\r
248 else {\r
249 draggable.el.insertBefore(item.el);\r
250 }\r
251 sortChange = true;\r
252 }\r
253 else if (this.horizontal && Math.abs(intersect.left - intersect.right) > (region.right - region.left) / 2) {\r
254 if (region.right > item.left && item.left > region.left) {\r
255 draggable.el.insertAfter(item.el);\r
256 }\r
257 else {\r
258 draggable.el.insertBefore(item.el);\r
259 }\r
260 sortChange = true;\r
261 }\r
262\r
263 if (sortChange) {\r
264 // We reset the draggable (initializes all the new start values)\r
265 draggable.reset();\r
266\r
267 // Move the draggable to its current location (since the transform is now\r
268 // different)\r
269 draggable.moveTo(region.left, region.top);\r
270\r
271 // Finally lets recalculate all the items boxes\r
272 this.calculateBoxes();\r
273 this.fireEvent('sortchange', this, draggable.el, this.el.select(this.itemSelector, false).indexOf(draggable.el.dom));\r
274 return;\r
275 }\r
276 }\r
277 }\r
278 },\r
279\r
280 /**\r
281 * @private\r
282 */\r
283 onDragEnd : function(draggable, e) {\r
284 draggable.destroy();\r
285 this.sorting = false;\r
286 this.fireEvent('sortend', this, draggable, e);\r
287 },\r
288\r
289 /**\r
290 * Enables sorting for this Sortable.\r
291 * This method is invoked immediately after construction of a Sortable unless\r
292 * the disabled configuration is set to `true`.\r
293 */\r
294 enable : function() {\r
295 this.el.on(this.startEventName, this.onStart, this, {delegate: this.itemSelector, holdThreshold: this.getDelay()});\r
296 this.disabled = false;\r
297 },\r
298\r
299 /**\r
300 * Disables sorting for this Sortable.\r
301 */\r
302 disable : function() {\r
303 this.el.un(this.startEventName, this.onStart, this);\r
304 this.disabled = true;\r
305 },\r
306\r
307 /**\r
308 * Method to determine whether this Sortable is currently disabled.\r
309 * @return {Boolean} The disabled state of this Sortable.\r
310 */\r
311 isDisabled: function() {\r
312 return this.disabled;\r
313 },\r
314\r
315 /**\r
316 * Method to determine whether this Sortable is currently sorting.\r
317 * @return {Boolean} The sorting state of this Sortable.\r
318 */\r
319 isSorting : function() {\r
320 return this.sorting;\r
321 },\r
322\r
323 /**\r
324 * Method to determine whether this Sortable is currently disabled.\r
325 * @return {Boolean} The disabled state of this Sortable.\r
326 */\r
327 isVertical : function() {\r
328 return this.vertical;\r
329 },\r
330\r
331 /**\r
332 * Method to determine whether this Sortable is currently sorting.\r
333 * @return {Boolean} The sorting state of this Sortable.\r
334 */\r
335 isHorizontal : function() {\r
336 return this.horizontal;\r
337 }\r
338});