Subversion Repositories SmartDukaan

Rev

Rev 1068 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1068 rajveer 1
/*
2
Copyright (c) 2009 Jordan Bach, http://www.utdallas.edu/~jrb048000/
3
 
4
Permission is hereby granted, free of charge, to any person obtaining a copy
5
of this software and associated documentation files (the "Software"), to deal
6
in the Software without restriction, including without limitation the rights
7
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
copies of the Software, and to permit persons to whom the Software is
9
furnished to do so, subject to the following conditions:
10
 
11
The above copyright notice and this permission notice shall be included in
12
all copies or substantial portions of the Software.
13
 
14
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
THE SOFTWARE.
21
*/
22
 
23
/*
24
List Reorder	 <http://www.utdallas.edu/~jrb048000/ListReorder/>
25
 
26
Enables drag-and-drop reordering of list items for any simple ordered <ol> or unordered <li> list.
27
 
28
Author: Jordan Bach
29
Version: 0.1
30
Created: January 1, 2009
31
License: MIT License
32
 
33
Constructor
34
	$(expr).ListOrder(options)
35
 
36
Methods:
37
	makeDefaultOrder - sets the current list order to [0, 1, 2, ...]
38
	restoreOrder - returns the list to its original order
39
 
40
Events:
41
	listorderchanged - Fired after a list item is dropped. The 2nd argument
42
		is a jQuery object representing the list that fired the event. 
43
		The 3rd argument is an array where the values represent
44
		the original index of each list item.
45
 
46
Options:
47
	itemHoverClass : 'itemHover',
48
	dragTargetClass : 'dragTarget',
49
	dropTargetClass : 'dropTarget',
50
	dragHandleClass : 'dragHandle'
51
 
52
*/
53
 
54
(function($){
55
 
56
$.fn.ListReorder = function (options) {
57
 
58
	$.fn.ListReorder.defaults = {
59
		itemHoverClass : 'itemHover',
60
		dragTargetClass : 'dragTarget',
61
		dropTargetClass : 'dropTarget',
62
		dragHandleClass : 'dragHandle',
63
		useDefaultDragHandle : false
64
	};
65
 
66
	var opts = $.extend({}, $.fn.ListReorder.defaults, options);
67
 
68
	return this.each(function() {
69
		var theList = $(this),   // The list (<ul>|<ol>)
70
			theItems = $('li', theList), // All <li> elements in the list
71
			dragActive = false,          // Are we currently dragging an item?
72
			dropTarget = null,           // The list placeholder
73
			dragTarget = null,           // The element currently being dragged
74
			dropIndex = -1,           	 // The list index of the dropTarget
75
			offset = {},				 // Positions the mouse in the dragTarget
76
			listOrder = [],				 // Keeps track of order relative to original order
77
			ref = this;
78
 
79
		theList.mouseout(ul_mouseout);
80
 
81
		// Create the drag target
82
		dragTarget = $('<div></div>');
83
		dragTarget.insertAfter(theList);
84
		dragTarget.hide();
85
		dragTarget.css('position', 'absolute');
86
		dragTarget.addClass(opts.dragTargetClass);
87
 
88
		for (var i = 0; i < theItems.length; i++)
89
			listOrder.push(i);
90
 
91
		resetList();
92
 
93
		function resetList() {	
94
			theItems = $('li', theList),
95
 
96
			// For each <li> in the list
97
			theItems.each(function() {
98
				var li = $(this);
99
 
100
				var dragHandle = $('<span></span>');
101
				dragHandle.addClass(opts.dragHandleClass)
102
					.mouseover(li_mouseover)
103
					.mousedown(dragHandle_mousedown);
104
 
105
				if (opts.useDefaultDragHandle)
106
					dragHandle.css({
107
						'display' : 'block',
108
						'float' : 'right',
109
						'width' : '10px',
110
						'height' : '10px',
111
						'border' : '2px solid #333',
112
						'background' : '#ccc',
113
						'cursor' : 'move'
114
					});
115
 
116
				$('.' + opts.dragHandleClass, li).remove();
117
				li.prepend(dragHandle);
118
			});
119
 
120
			clearListItemStyles();
121
		}
122
 
123
		// Return all list items to their default state
124
		function clearListItemStyles() {
125
			theItems.each(function() {
126
				var li = $(this);
127
				li.removeClass(opts.itemHoverClass);
128
				li.removeClass(opts.dropTargetClass);
129
			});
130
		}
131
 
132
		// Handle any cleanup when the mouse leaves the list
133
		function ul_mouseout() {
134
			if (!dragActive)
135
				clearListItemStyles();
136
		}
137
 
138
		// Add a hover class to a list item on mouseover
139
		function li_mouseover() {
140
			if (!dragActive) {
141
				clearListItemStyles();
142
				$(this).parent().addClass(opts.itemHoverClass);
143
			}
144
		}
145
 
146
		// Prepare the list for dragging an item
147
		function dragHandle_mousedown(e) {
148
			var li = $(this).parent();
149
 
150
			dragActive = true;
151
			dropIndex = theItems.index(li);
152
 
153
			// Show the drag target
154
			dragTarget.html(li.html());
155
			dragTarget.css('display', 'block');
156
			offset.top = e.pageY - li.offset().top;
157
			offset.left = e.pageX - li.offset().left;
158
			updateDragTargetPos(e);
159
 
160
			// Insert the placeholder
161
			dropTarget = li;
162
			dropTarget.html('');
163
			dropTarget.css('height', dragTarget.css('height'));
164
			dragTarget.css('width', dropTarget.width() + 'px');
165
			dropTarget.addClass(opts.dropTargetClass);
166
 
167
			// Disable Text and DOM selection
168
			$(document).disableTextSelect();
169
 
170
			$(document).mouseup(dragHandle_mouseup);
171
			$(document).mousemove(document_mousemove);	
172
		}
173
 
174
		// If this were on the element, we could lose the drag on the element 
175
		// if we move the mouse too fast
176
		function document_mousemove(e) {
177
			if (dragActive) {
178
				// drag target follows mouse cursor
179
				updateDragTargetPos(e);
180
 
181
				// Don't do mess with drop index if we are above or below the list
182
				if (y_mid(dragTarget) > y_bot(theList) 
183
					|| y_mid(dragTarget) < y_top(theList)) {
184
					return;
185
				}
186
 
187
				// detect position of drag target relative to list items
188
				// and swap drop target and neighboring item if necessary
189
				if (y_mid(dragTarget) + 5 < y_top(dropTarget)) {
190
					swapListItems(dropIndex, --dropIndex);
191
				} else if (y_mid(dragTarget) - 5 > y_bot(dropTarget)) {
192
					swapListItems(dropIndex, ++dropIndex);
193
				}
194
			}
195
		}
196
 
197
		function dragHandle_mouseup() {
198
			// Restore the drop target
199
			dropTarget.html(dragTarget.html());
200
			dropTarget.removeClass(opts.dragTargetClass);
201
			dropTarget = null;
202
 
203
			// Hide the drag target
204
			dragTarget.css('display', 'none');
205
 
206
			dragActive = false;
207
			dragTarget.unbind('mouseup', dragHandle_mouseup);
208
			$(document).unbind('mousemove', document_mousemove);
209
			resetList();
210
 
211
			theList.trigger('listorderchanged', [theList, listOrder]);
212
 
213
			// Re-enable text selection
214
			$(document).enableTextSelect();
215
			$(document).unbind('mouseup', dragHandle_mouseup);
216
		}
217
 
218
		function updateDragTargetPos(e) {
219
			dragTarget.css({ 
220
				'top' : e.pageY - offset.top + 'px',
221
				'left' : e.pageX - offset.left + 'px'
222
			});
223
		}
224
 
225
		// Change the order of two list items
226
		function swapListItems(oldDropIndex, newDropIndex) {
227
			// keep indices in bounds
228
			if (dropIndex < 0) {
229
				dropIndex = 0;
230
				return;
231
			} else if (dropIndex >= theItems.length) {
232
				dropIndex = theItems.length - 1;
233
				return;
234
			}
235
 
236
			var t = listOrder[oldDropIndex];
237
			listOrder[oldDropIndex] = listOrder[newDropIndex];
238
			listOrder[newDropIndex] = t;
239
 
240
			// swap list items
241
			var oldDropTarget = theItems.get(oldDropIndex),
242
				newDropTarget = theItems.get(newDropIndex),
243
				temp1 = $(oldDropTarget).clone(true);
244
				temp2 = $(newDropTarget).clone(true);
245
 
246
			$(oldDropTarget).replaceWith(temp2)
247
				.mouseover(li_mouseover)
248
				.mousedown(dragHandle_mousedown);
249
			$(newDropTarget).replaceWith(temp1)
250
				.mouseover(li_mouseover)
251
				.mousedown(dragHandle_mousedown);
252
 
253
			// reset so it is valid on next use
254
			theItems = $('li', theList);
255
			dropTarget = $(theItems.get(newDropIndex));
256
		}
257
 
258
		function y_top(jq) {
259
			return jq.offset().top;
260
		}
261
 
262
		function y_mid(jq) {
263
			return (y_top(jq) + y_bot(jq)) / 2
264
		}
265
 
266
		function y_bot(jq) {
267
			return jq.offset().top + jq.outerHeight();
268
		}
269
 
270
		this.makeDefaultOrder = function() {
271
			for (var i = 0; i < listOrder.length; i++)
272
				listOrder[i] = i;
273
		}
274
 
275
		this.restoreOrder = function() { 
276
			for (var i = 0; i < theItems.length; i++) {
277
				if (i != listOrder[i]) {
278
					var k = 0;
279
					for (; k < listOrder.length; k++)
280
						if (listOrder[k] == i)
281
							break;
282
					swapListItems(i, k);
283
				}
284
			}
285
			theList.trigger('listorderchanged', [theList, listOrder]);
286
		}
287
	});
288
}
289
})(jQuery);