]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | /**\r |
2 | * @class Ext.plugin.SortableList\r | |
3 | * @extends Ext.Component\r | |
4 | * The SortableList plugin gives your list items the ability to be reordered by tapping and \r | |
5 | * dragging elements within the item. \r | |
6 | *\r | |
7 | * The list-sortablehandle is not added to your tpl by default, so it's important that you \r | |
8 | * manually include it. It's also important to recognize that list-items are not draggable \r | |
9 | * themselves. You must add an element to the itemTpl for it to be dragged.\r | |
10 | *\r | |
11 | * Ext.Viewport.add({\r | |
12 | * xtype: 'list',\r | |
13 | * infinite: true,\r | |
14 | * plugins: 'sortablelist',\r | |
15 | * itemTpl: '<span class="myStyle ' + Ext.baseCSSPrefix + 'list-sortablehandle"></span>{text}',\r | |
16 | * data: [{\r | |
17 | * text: 'Item 1'\r | |
18 | * }, {\r | |
19 | * text: 'Item 2'\r | |
20 | * }, {\r | |
21 | * text: 'Item 3'\r | |
22 | * }]\r | |
23 | * });\r | |
24 | *\r | |
25 | * The CSS for MyStyle can be anything that creates an element to tap and drag. For this \r | |
26 | * example we made a simple rectangle like so:\r | |
27 | *\r | |
28 | * .myStyle{\r | |
29 | * width:30px;\r | |
30 | * height:20px;\r | |
31 | * background:gray;\r | |
32 | * float:left;\r | |
33 | * }\r | |
34 | * \r | |
35 | * Note: You must have infinite set to 'true' when using the SortableList plugin.\r | |
36 | * \r | |
37 | */\r | |
38 | Ext.define('Ext.plugin.SortableList', {\r | |
39 | extend: 'Ext.Component',\r | |
40 | \r | |
41 | alias: 'plugin.sortablelist',\r | |
42 | \r | |
43 | mixins: ['Ext.mixin.Hookable'],\r | |
44 | \r | |
45 | config: {\r | |
46 | list: null,\r | |
47 | handleSelector: '.' + Ext.baseCSSPrefix + 'list-sortablehandle'\r | |
48 | },\r | |
49 | \r | |
50 | init: function(list) {\r | |
51 | this.setList(list);\r | |
52 | },\r | |
53 | \r | |
54 | updateList: function(list) {\r | |
55 | if (list) {\r | |
56 | if (list.initialized) {\r | |
57 | this.attachListeners();\r | |
58 | }\r | |
59 | else {\r | |
60 | list.on({\r | |
61 | initialize: 'attachListeners',\r | |
62 | scope: this,\r | |
63 | single: true\r | |
64 | });\r | |
65 | }\r | |
66 | }\r | |
67 | },\r | |
68 | \r | |
69 | attachListeners: function() {\r | |
70 | var list = this.getList(),\r | |
71 | scrollerElement = list.getScrollable().getElement();\r | |
72 | \r | |
73 | this.scrollerElement = scrollerElement;\r | |
74 | \r | |
75 | scrollerElement.onBefore({\r | |
76 | dragstart: 'onScrollerDragStart',\r | |
77 | scope: this\r | |
78 | });\r | |
79 | },\r | |
80 | \r | |
81 | onScrollerDragStart: function(e, target) {\r | |
82 | if (Ext.DomQuery.is(target, this.getHandleSelector())) {\r | |
83 | if (!this.animating) {\r | |
84 | this.onDragStart(e, target);\r | |
85 | }\r | |
86 | return false;\r | |
87 | }\r | |
88 | },\r | |
89 | \r | |
90 | onDragStart: function(e) {\r | |
91 | var row = Ext.getCmp(e.getTarget('.' + Ext.baseCSSPrefix + 'list-item').id),\r | |
92 | list = this.getList(),\r | |
93 | store = list.getStore();\r | |
94 | \r | |
95 | this.scrollerElement.on({\r | |
96 | drag: 'onDrag',\r | |
97 | dragend: 'onDragEnd',\r | |
98 | scope: this\r | |
99 | });\r | |
100 | \r | |
101 | this.positionMap = list.getItemMap();\r | |
102 | this.listStore = store;\r | |
103 | this.previousIndexDistance = 0;\r | |
104 | \r | |
105 | this.dragRow = row;\r | |
106 | this.dragRecord = row.getRecord();\r | |
107 | \r | |
108 | this.dragRowIndex = this.currentDragRowIndex = row.$dataIndex;\r | |
109 | this.dragRowHeight = this.positionMap.getItemHeight(this.dragRowIndex);\r | |
110 | \r | |
111 | if (list.getInfinite()) {\r | |
112 | this.startTranslate = this.positionMap.map[this.dragRowIndex];\r | |
113 | } else {\r | |
114 | row.translate(0, 0);\r | |
115 | this.startTranslate = 0;\r | |
116 | }\r | |
117 | \r | |
118 | row.addCls(Ext.baseCSSPrefix + 'list-item-dragging');\r | |
119 | },\r | |
120 | \r | |
121 | onDrag: function(e) {\r | |
122 | var list = this.getList(),\r | |
123 | listItems = list.listItems,\r | |
124 | store = list.getStore(),\r | |
125 | collection = list.getStore().data,\r | |
126 | dragRow = this.dragRow,\r | |
127 | dragRecordKey = dragRow.id,\r | |
128 | listItemInfo = list.getListItemInfo(),\r | |
129 | positionMap = this.positionMap,\r | |
130 | distance = 0,\r | |
131 | i, item, ln, targetItem, targetIndex, itemIndex,\r | |
132 | swapIndex, swapPosition, record, swapKey, draggingUp;\r | |
133 | \r | |
134 | this.dragRowPosition = this.startTranslate + e.deltaY;\r | |
135 | dragRow.translate(0, this.dragRowPosition);\r | |
136 | \r | |
137 | targetIndex = positionMap.findIndex(this.dragRowPosition + (this.dragRowHeight / 2));\r | |
138 | targetItem = list.getItemAt(targetIndex);\r | |
139 | \r | |
140 | if (targetItem) {\r | |
141 | distance = targetIndex - this.currentDragRowIndex;\r | |
142 | \r | |
143 | if (distance !== 0) {\r | |
144 | draggingUp = distance < 0;\r | |
145 | \r | |
146 | for (i = 0, ln = Math.abs(distance); i < ln; i++) {\r | |
147 | if (draggingUp) {\r | |
148 | swapIndex = this.currentDragRowIndex - i;\r | |
149 | item = list.getItemAt(swapIndex - 1);\r | |
150 | } else {\r | |
151 | swapIndex = this.currentDragRowIndex + i;\r | |
152 | item = list.getItemAt(swapIndex + 1);\r | |
153 | }\r | |
154 | \r | |
155 | swapPosition = positionMap.map[swapIndex];\r | |
156 | \r | |
157 | item.translate(0, swapPosition);\r | |
158 | \r | |
159 | record = item.getRecord();\r | |
160 | swapKey = record.id;\r | |
161 | \r | |
162 | Ext.Array.remove(collection.items, record);\r | |
163 | collection.items.splice(swapIndex, 0, record);\r | |
164 | collection.indices[dragRecordKey] = collection.indices[swapKey];\r | |
165 | collection.indices[swapKey] = swapIndex;\r | |
166 | \r | |
167 | list.updateListItem(item, swapIndex, listItemInfo);\r | |
168 | item.$position = swapPosition;\r | |
169 | }\r | |
170 | \r | |
171 | itemIndex = listItems.indexOf(dragRow);\r | |
172 | Ext.Array.remove(listItems, dragRow);\r | |
173 | listItems.splice(itemIndex + distance, 0, dragRow);\r | |
174 | \r | |
175 | dragRow.$dataIndex = targetIndex;\r | |
176 | dragRow.$position = positionMap.map[targetIndex];\r | |
177 | \r | |
178 | this.currentDragRowIndex = targetIndex;\r | |
179 | }\r | |
180 | }\r | |
181 | },\r | |
182 | \r | |
183 | onDragEnd: function() {\r | |
184 | var me = this,\r | |
185 | row = me.dragRow,\r | |
186 | list = me.getList(),\r | |
187 | listItemInfo = list.getListItemInfo(),\r | |
188 | position = row.$position;\r | |
189 | \r | |
190 | me.scrollerElement.un({\r | |
191 | drag: 'onDrag',\r | |
192 | dragend: 'onDragEnd',\r | |
193 | scope: me\r | |
194 | });\r | |
195 | \r | |
196 | me.animating = true;\r | |
197 | \r | |
198 | row.getTranslatable().on('animationend', function() {\r | |
199 | row.removeCls(Ext.baseCSSPrefix + 'list-item-dragging');\r | |
200 | \r | |
201 | var currentIdx = this.currentDragRowIndex,\r | |
202 | dragIdx = this.dragRowIndex;\r | |
203 | \r | |
204 | if (currentIdx !== dragIdx) {\r | |
205 | list.updateListItem(row, row.$dataIndex, listItemInfo);\r | |
206 | row.$position = position;\r | |
207 | \r | |
208 | list.fireEvent('dragsort', list, row, currentIdx, dragIdx);\r | |
209 | }\r | |
210 | me.animating = false;\r | |
211 | }, me, {single: true});\r | |
212 | \r | |
213 | row.translate(0, position, {duration: 100});\r | |
214 | }\r | |
215 | });\r |