1// jQuery List DragSort v0.5.2 2// Website: http://dragsort.codeplex.com/ 3// License: http://dragsort.codeplex.com/license 4 5(function($) { 6 7 $.fn.dragsort = function(options) { 8 if (options == "destroy") { 9 $(this.selector).trigger("dragsort-uninit"); 10 return; 11 } 12 13 var opts = $.extend({}, $.fn.dragsort.defaults, options); 14 var lists = []; 15 var list = null, lastPos = null; 16 17 this.each(function(i, cont) { 18 19 //if list container is table, the browser automatically wraps rows in tbody if not specified so change list container to tbody so that children returns rows as user expected 20 if ($(cont).is("table") && $(cont).children().length == 1 && $(cont).children().is("tbody")) 21 cont = $(cont).children().get(0); 22 23 var newList = { 24 draggedItem: null, 25 placeHolderItem: null, 26 pos: null, 27 offset: null, 28 offsetLimit: null, 29 scroll: null, 30 container: cont, 31 32 init: function() { 33 //set options to default values if not set 34 opts.tagName = opts.tagName == "" ? ($(this.container).children().length == 0 ? "li" : $(this.container).children().get(0).tagName.toLowerCase()) : opts.tagName; 35 if (opts.itemSelector == "") 36 opts.itemSelector = opts.tagName; 37 if (opts.dragSelector == "") 38 opts.dragSelector = opts.tagName; 39 if (opts.placeHolderTemplate == "") 40 opts.placeHolderTemplate = "<" + opts.tagName + "> </" + opts.tagName + ">"; 41 42 //listidx allows reference back to correct list variable instance 43 $(this.container).attr("data-listidx", i).mousedown(this.grabItem).bind("dragsort-uninit", this.uninit); 44 this.styleDragHandlers(true); 45 }, 46 47 uninit: function() { 48 var list = lists[$(this).attr("data-listidx")]; 49 $(list.container).unbind("mousedown", list.grabItem).unbind("dragsort-uninit"); 50 list.styleDragHandlers(false); 51 }, 52 53 getItems: function() { 54 return $(this.container).children(opts.itemSelector); 55 }, 56 57 styleDragHandlers: function(cursor) { 58 this.getItems().map(function() { return $(this).is(opts.dragSelector) ? this : $(this).find(opts.dragSelector).get(); }).css("cursor", cursor ? "pointer" : ""); 59 }, 60 61 grabItem: function(e) { 62 var list = lists[$(this).attr("data-listidx")]; 63 var item = $(e.target).closest("[data-listidx] > " + opts.tagName).get(0); 64 var insideMoveableItem = list.getItems().filter(function() { return this == item; }).length > 0; 65 66 //if not left click or if clicked on excluded element (e.g. text box) or not a moveable list item return 67 if (e.which != 1 || $(e.target).is(opts.dragSelectorExclude) || $(e.target).closest(opts.dragSelectorExclude).length > 0 || !insideMoveableItem) 68 return; 69 70 //prevents selection, stops issue on Fx where dragging hyperlink doesn't work and on IE where it triggers mousemove even though mouse hasn't moved, 71 //does also stop being able to click text boxes hence dragging on text boxes by default is disabled in dragSelectorExclude 72 //e.preventDefault(); 73 74 //change cursor to move while dragging 75 var dragHandle = e.target; 76 while (!$(dragHandle).is(opts.dragSelector)) { 77 if (dragHandle == this) return; 78 dragHandle = dragHandle.parentNode; 79 } 80 $(dragHandle).attr("data-cursor", $(dragHandle).css("cursor")); 81 $(dragHandle).css("cursor", "move"); 82 83 //on mousedown wait for movement of mouse before triggering dragsort script (dragStart) to allow clicking of hyperlinks to work 84 var listElem = this; 85 var trigger = function() { 86 list.dragStart.call(listElem, e); 87 $(list.container).unbind("mousemove", trigger); 88 }; 89 $(list.container).mousemove(trigger).mouseup(function() { $(list.container).unbind("mousemove", trigger); $(dragHandle).css("cursor", $(dragHandle).attr("data-cursor")); }); 90 }, 91 92 dragStart: function(e) { 93 if (list != null && list.draggedItem != null) 94 list.dropItem(); 95 96 list = lists[$(this).attr("data-listidx")]; 97 list.draggedItem = $(e.target).closest("[data-listidx] > " + opts.tagName) 98 99 //record current position so on dragend we know if the dragged item changed position or not, not using getItems to allow dragsort to restore dragged item to original location in relation to fixed items 100 list.draggedItem.attr("data-origpos", $(this).attr("data-listidx") + "-" + $(list.container).children().index(list.draggedItem)); 101 102 //calculate mouse offset relative to draggedItem 103 var mt = parseInt(list.draggedItem.css("marginTop")); 104 var ml = parseInt(list.draggedItem.css("marginLeft")); 105 list.offset = list.draggedItem.offset(); 106 list.offset.top = e.pageY - list.offset.top + (isNaN(mt) ? 0 : mt) - 1; 107 list.offset.left = e.pageX - list.offset.left + (isNaN(ml) ? 0 : ml) - 1; 108 109 //calculate box the dragged item can't be dragged outside of 110 if (!opts.dragBetween) { 111 var containerHeight = $(list.container).outerHeight() == 0 ? Math.max(1, Math.round(0.5 + list.getItems().length * list.draggedItem.outerWidth() / $(list.container).outerWidth())) * list.draggedItem.outerHeight() : $(list.container).outerHeight(); 112 list.offsetLimit = $(list.container).offset(); 113 list.offsetLimit.right = list.offsetLimit.left + $(list.container).outerWidth() - list.draggedItem.outerWidth(); 114 list.offsetLimit.bottom = list.offsetLimit.top + containerHeight - list.draggedItem.outerHeight(); 115 } 116 117 //create placeholder item 118 var h = list.draggedItem.height(); 119 var w = list.draggedItem.width(); 120 if (opts.tagName == "tr") { 121 list.draggedItem.children().each(function() { $(this).width($(this).width()); }); 122 list.placeHolderItem = list.draggedItem.clone().attr("data-placeholder", true); 123 list.draggedItem.after(list.placeHolderItem); 124 //list.placeHolderItem.children().each(function() { $(this).css({ borderWidth:0, width: $(this).width() + 1, height: $(this).height() + 1 }).html(" "); }); 125 list.placeHolderItem.children().each(function() { $(this).html(" "); }); 126 } else { 127 list.draggedItem.after(opts.placeHolderTemplate); 128 list.placeHolderItem = list.draggedItem.next().css({ height: h, width: w }).attr("data-placeholder", true); 129 } 130 131 if (opts.tagName == "td") { 132 var listTable = list.draggedItem.closest("table").get(0); 133 $("<table id='" + listTable.id + "' style='border-width: 0px;' class='dragSortItem " + listTable.className + "'><tr></tr></table>").appendTo("body").children().append(list.draggedItem); 134 } 135 136 //style draggedItem while dragging 137 var orig = list.draggedItem.attr("style"); 138 list.draggedItem.attr("data-origstyle", orig ? orig : ""); 139 list.draggedItem.css({ position: "absolute", opacity: 0.8, "z-index": 999, height: h, width: w }); 140 141 //auto-scroll setup 142 list.scroll = { moveX: 0, moveY: 0, maxX: $(document).width() - $(window).width(), maxY: $(document).height() - $(window).height() }; 143 list.scroll.scrollY = window.setInterval(function() { 144 if (opts.scrollContainer != window) { 145 $(opts.scrollContainer).scrollTop($(opts.scrollContainer).scrollTop() + list.scroll.moveY); 146 return; 147 } 148 var t = $(opts.scrollContainer).scrollTop(); 149 if (list.scroll.moveY > 0 && t < list.scroll.maxY || list.scroll.moveY < 0 && t > 0) { 150 $(opts.scrollContainer).scrollTop(t + list.scroll.moveY); 151 list.draggedItem.css("top", list.draggedItem.offset().top + list.scroll.moveY + 1); 152 } 153 }, 10); 154 list.scroll.scrollX = window.setInterval(function() { 155 if (opts.scrollContainer != window) { 156 $(opts.scrollContainer).scrollLeft($(opts.scrollContainer).scrollLeft() + list.scroll.moveX); 157 return; 158 } 159 var l = $(opts.scrollContainer).scrollLeft(); 160 if (list.scroll.moveX > 0 && l < list.scroll.maxX || list.scroll.moveX < 0 && l > 0) { 161 $(opts.scrollContainer).scrollLeft(l + list.scroll.moveX); 162 list.draggedItem.css("left", list.draggedItem.offset().left + list.scroll.moveX + 1); 163 } 164 }, 10); 165 166 //misc 167 $(lists).each(function(i, l) { l.createDropTargets(); l.buildPositionTable(); }); 168 list.setPos(e.pageX, e.pageY); 169 $(document).bind("mousemove", list.swapItems); 170 $(document).bind("mouseup", list.dropItem); 171 if (opts.scrollContainer != window) 172 $(window).bind("wheel", list.wheel); 173 }, 174 175 //set position of draggedItem 176 setPos: function(x, y) { 177 //remove mouse offset so mouse cursor remains in same place on draggedItem instead of top left corner 178 var top = y - this.offset.top; 179 var left = x - this.offset.left; 180 181 //limit top, left to within box draggedItem can't be dragged outside of 182 if (!opts.dragBetween) { 183 top = Math.min(this.offsetLimit.bottom, Math.max(top, this.offsetLimit.top)); 184 left = Math.min(this.offsetLimit.right, Math.max(left, this.offsetLimit.left)); 185 } 186 187 //adjust top & left calculations to parent offset 188 var parent = this.draggedItem.offsetParent().not("body").offset(); //offsetParent returns body even when it's static, if not static offset is only factoring margin 189 if (parent != null) { 190 top -= parent.top; 191 left -= parent.left; 192 } 193 194 //set x or y auto-scroll amount 195 if (opts.scrollContainer == window) { 196 y -= $(window).scrollTop(); 197 x -= $(window).scrollLeft(); 198 y = Math.max(0, y - $(window).height() + 5) + Math.min(0, y - 5); 199 x = Math.max(0, x - $(window).width() + 5) + Math.min(0, x - 5); 200 } else { 201 var cont = $(opts.scrollContainer); 202 var offset = cont.offset(); 203 y = Math.max(0, y - cont.height() - offset.top) + Math.min(0, y - offset.top); 204 x = Math.max(0, x - cont.width() - offset.left) + Math.min(0, x - offset.left); 205 } 206 207 list.scroll.moveX = x == 0 ? 0 : x * opts.scrollSpeed / Math.abs(x); 208 list.scroll.moveY = y == 0 ? 0 : y * opts.scrollSpeed / Math.abs(y); 209 210 //move draggedItem to new mouse cursor location 211 this.draggedItem.css({ top: top, left: left }); 212 }, 213 214 //if scroll container is a div allow mouse wheel to scroll div instead of window when mouse is hovering over 215 wheel: function(e) { 216 if (list && opts.scrollContainer != window) { 217 var cont = $(opts.scrollContainer); 218 var offset = cont.offset(); 219 e = e.originalEvent; 220 if (e.clientX > offset.left && e.clientX < offset.left + cont.width() && e.clientY > offset.top && e.clientY < offset.top + cont.height()) { 221 var deltaY = (e.deltaMode == 0 ? 1 : 10) * e.deltaY; 222 cont.scrollTop(cont.scrollTop() + deltaY); 223 e.preventDefault(); 224 } 225 } 226 }, 227 228 //build a table recording all the positions of the moveable list items 229 buildPositionTable: function() { 230 var pos = []; 231 this.getItems().not([list.draggedItem[0], list.placeHolderItem[0]]).each(function(i) { 232 var loc = $(this).offset(); 233 loc.right = loc.left + $(this).outerWidth(); 234 loc.bottom = loc.top + $(this).outerHeight(); 235 loc.elm = this; 236 pos[i] = loc; 237 }); 238 this.pos = pos; 239 }, 240 241 dropItem: function() { 242 if (list.draggedItem == null) 243 return; 244 245 //list.draggedItem.attr("style", "") doesn't work on IE8 and jQuery 1.5 or lower 246 //list.draggedItem.removeAttr("style") doesn't work on chrome and jQuery 1.6 (works jQuery 1.5 or lower) 247 var orig = list.draggedItem.attr("data-origstyle"); 248 list.draggedItem.attr("style", orig); 249 if (orig == "") 250 list.draggedItem.removeAttr("style"); 251 list.draggedItem.removeAttr("data-origstyle"); 252 253 list.styleDragHandlers(true); 254 255 list.placeHolderItem.before(list.draggedItem); 256 list.placeHolderItem.remove(); 257 258 $("[data-droptarget], .dragSortItem").remove(); 259 260 window.clearInterval(list.scroll.scrollY); 261 window.clearInterval(list.scroll.scrollX); 262 263 //if position changed call dragEnd 264 if (list.draggedItem.attr("data-origpos") != $(lists).index(list) + "-" + $(list.container).children().index(list.draggedItem)) 265 if (opts.dragEnd.apply(list.draggedItem) == false) { //if dragEnd returns false revert order 266 var pos = list.draggedItem.attr("data-origpos").split('-'); 267 var nextItem = $(lists[pos[0]].container).children().not(list.draggedItem).eq(pos[1]); 268 if (nextItem.length > 0) 269 nextItem.before(list.draggedItem); 270 else if (pos[1] == 0) //was the only item in list 271 $(lists[pos[0]].container).prepend(list.draggedItem); 272 else //was the last item in list 273 $(lists[pos[0]].container).append(list.draggedItem); 274 } 275 list.draggedItem.removeAttr("data-origpos"); 276 277 list.draggedItem = null; 278 $(document).unbind("mousemove", list.swapItems); 279 $(document).unbind("mouseup", list.dropItem); 280 if (opts.scrollContainer != window) 281 $(window).unbind("wheel", list.wheel); 282 return false;
283 }, 284 285 //swap the draggedItem (represented visually by placeholder) with the list item the it has been dragged on top of 286 swapItems: function(e) { 287 if (list.draggedItem == null) 288 return false; 289 290 //move draggedItem to mouse location 291 list.setPos(e.pageX, e.pageY); 292 293 //retrieve list and item position mouse cursor is over 294 var ei = list.findPos(e.pageX, e.pageY); 295 var nlist = list; 296 for (var i = 0; ei == -1 && opts.dragBetween && i < lists.length; i++) { 297 ei = lists[i].findPos(e.pageX, e.pageY); 298 nlist = lists[i]; 299 } 300 301 //if not over another moveable list item return 302 if (ei == -1) 303 return false; 304 305 //save fixed items locations 306 var children = function() { return $(nlist.container).children().not(nlist.draggedItem); }; 307 var fixed = children().not(opts.itemSelector).each(function(i) { this.idx = children().index(this); }); 308 309 //if moving draggedItem up or left place placeHolder before list item the dragged item is hovering over otherwise place it after 310 if (lastPos == null || lastPos.top > list.draggedItem.offset().top || lastPos.left > list.draggedItem.offset().left) 311 $(nlist.pos[ei].elm).before(list.placeHolderItem); 312 else 313 $(nlist.pos[ei].elm).after(list.placeHolderItem); 314 315 //restore fixed items location 316 fixed.each(function() { 317 var elm = children().eq(this.idx).get(0); 318 if (this != elm && children().index(this) < this.idx) 319 $(this).insertAfter(elm); 320 else if (this != elm) 321 $(this).insertBefore(elm); 322 }); 323 324 //misc 325 $(lists).each(function(i, l) { l.createDropTargets(); l.buildPositionTable(); }); 326 lastPos = list.draggedItem.offset(); 327 return false; 328 }, 329 330 //returns the index of the list item the mouse is over 331 findPos: function(x, y) { 332 for (var i = 0; i < this.pos.length; i++) { 333 if (this.pos[i].left < x && this.pos[i].right > x && this.pos[i].top < y && this.pos[i].bottom > y) 334 return i; 335 } 336 return -1; 337 }, 338 339 //create drop targets which are placeholders at the end of other lists to allow dragging straight to the last position 340 createDropTargets: function() { 341 if (!opts.dragBetween) 342 return; 343 344 $(lists).each(function() { 345 var ph = $(this.container).find("[data-placeholder]"); 346 var dt = $(this.container).find("[data-droptarget]"); 347 if (ph.length > 0 && dt.length > 0) 348 dt.remove(); 349 else if (ph.length == 0 && dt.length == 0) { 350 if (opts.tagName == "td") 351 $(opts.placeHolderTemplate).attr("data-droptarget", true).appendTo(this.container); 352 else 353 //list.placeHolderItem.clone().removeAttr("data-placeholder") crashes in IE7 and jquery 1.5.1 (doesn't in jquery 1.4.2 or IE8) 354 $(this.container).append(list.placeHolderItem.removeAttr("data-placeholder").clone().attr("data-droptarget", true)); 355 356 list.placeHolderItem.attr("data-placeholder", true); 357 } 358 }); 359 } 360 }; 361 362 newList.init(); 363 lists.push(newList); 364 }); 365 366 return this; 367 }; 368 369 $.fn.dragsort.defaults = { 370 tagName:"", 371 itemSelector: "", 372 dragSelector: "", 373 dragSelectorExclude: "input, textarea", 374 dragEnd: function() { }, 375 dragBetween: false, 376 placeHolderTemplate: "", 377 scrollContainer: window, 378 scrollSpeed: 5 379 }; 380 381})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.