|
| 1 | +/* |
| 2 | + * HTML5 Sortable jQuery Plugin |
| 3 | + * https://github.com/voidberg/html5select2sortable |
| 4 | + * |
| 5 | + * Original code copyright 2012 Ali Farhadi. |
| 6 | + * This version is mantained by Alexandru Badiu <[email protected]> |
| 7 | + * |
| 8 | + * Thanks to the following contributors: andyburke, bistoco, daemianmack, drskullster, flying-sheep, OscarGodson, Parikshit N. Samant, rodolfospalenza, ssafejava |
| 9 | + * |
| 10 | + * Released under the MIT license. |
| 11 | + */ |
| 12 | +'use strict'; |
| 13 | + |
| 14 | +(function ($) { |
| 15 | + var dragging, draggingHeight, placeholders = $(); |
| 16 | + $.fn.select2sortable = function (options) { |
| 17 | + var method = String(options); |
| 18 | + |
| 19 | + options = $.extend({ |
| 20 | + connectWith: false, |
| 21 | + placeholder: null, |
| 22 | + dragImage: null |
| 23 | + }, options); |
| 24 | + |
| 25 | + return this.each(function () { |
| 26 | + |
| 27 | + var index, items = $(this).children(options.items), handles = options.handle ? items.find(options.handle) : items; |
| 28 | + |
| 29 | + if (method === 'reload') { |
| 30 | + $(this).children(options.items).off('dragstart.h5s dragend.h5s selectstart.h5s dragover.h5s dragenter.h5s drop.h5s'); |
| 31 | + } |
| 32 | + if (/^enable|disable|destroy$/.test(method)) { |
| 33 | + var citems = $(this).children($(this).data('items')).attr('draggable', method === 'enable'); |
| 34 | + if (method === 'destroy') { |
| 35 | + $(this).off('sortupdate'); |
| 36 | + $(this).removeData('opts'); |
| 37 | + citems.add(this).removeData('connectWith items') |
| 38 | + .off('dragstart.h5s dragend.h5s dragover.h5s dragenter.h5s drop.h5s').off('sortupdate'); |
| 39 | + handles.off('selectstart.h5s'); |
| 40 | + } |
| 41 | + return; |
| 42 | + } |
| 43 | + |
| 44 | + var soptions = $(this).data('opts'); |
| 45 | + |
| 46 | + if (typeof soptions === 'undefined') { |
| 47 | + $(this).data('opts', options); |
| 48 | + } |
| 49 | + else { |
| 50 | + options = soptions; |
| 51 | + } |
| 52 | + |
| 53 | + var startParent, newParent; |
| 54 | + var placeholder = ( options.placeholder === null ) ? $('<' + (/^ul|ol$/i.test(this.tagName) ? 'li' : 'div') + ' class="select2sortable-placeholder"/>') : $(options.placeholder).addClass('select2sortable-placeholder'); |
| 55 | + |
| 56 | + $(this).data('items', options.items); |
| 57 | + placeholders = placeholders.add(placeholder); |
| 58 | + if (options.connectWith) { |
| 59 | + $(options.connectWith).add(this).data('connectWith', options.connectWith); |
| 60 | + } |
| 61 | + |
| 62 | + items.attr('role', 'option'); |
| 63 | + items.attr('aria-grabbed', 'false'); |
| 64 | + |
| 65 | + // Setup drag handles |
| 66 | + handles.attr('draggable', 'true').not('a[href], img').on('selectstart.h5s', function() { |
| 67 | + if (this.dragDrop) { |
| 68 | + this.dragDrop(); |
| 69 | + } |
| 70 | + return false; |
| 71 | + }).end(); |
| 72 | + |
| 73 | + // Handle drag events on draggable items |
| 74 | + items.on('dragstart.h5s', function(e) { |
| 75 | + var dt = e.originalEvent.dataTransfer; |
| 76 | + dt.effectAllowed = 'move'; |
| 77 | + dt.setData('text', ''); |
| 78 | + |
| 79 | + if (options.dragImage && dt.setDragImage) { |
| 80 | + dt.setDragImage(options.dragImage, 0, 0); |
| 81 | + } |
| 82 | + |
| 83 | + index = (dragging = $(this)).addClass('select2sortable-dragging').attr('aria-grabbed', 'true').index(); |
| 84 | + draggingHeight = dragging.outerHeight(); |
| 85 | + startParent = $(this).parent(); |
| 86 | + dragging.parent().triggerHandler('sortstart', {item: dragging, startparent: startParent}); |
| 87 | + }).on('dragend.h5s',function () { |
| 88 | + if (!dragging) { |
| 89 | + return; |
| 90 | + } |
| 91 | + dragging.removeClass('select2sortable-dragging').attr('aria-grabbed', 'false').show(); |
| 92 | + placeholders.detach(); |
| 93 | + newParent = $(this).parent(); |
| 94 | + if (index !== dragging.index() || startParent.get(0) !== newParent.get(0)) { |
| 95 | + dragging.parent().triggerHandler('sortupdate', {item: dragging, oldindex: index, startparent: startParent, endparent: newParent}); |
| 96 | + } |
| 97 | + dragging = null; |
| 98 | + draggingHeight = null; |
| 99 | + }).add([this, placeholder]).on('dragover.h5s dragenter.h5s drop.h5s', function(e) { |
| 100 | + if (!items.is(dragging) && options.connectWith !== $(dragging).parent().data('connectWith')) { |
| 101 | + return true; |
| 102 | + } |
| 103 | + if (e.type === 'drop') { |
| 104 | + e.stopPropagation(); |
| 105 | + placeholders.filter(':visible').after(dragging); |
| 106 | + dragging.trigger('dragend.h5s'); |
| 107 | + return false; |
| 108 | + } |
| 109 | + e.preventDefault(); |
| 110 | + e.originalEvent.dataTransfer.dropEffect = 'move'; |
| 111 | + if (items.is(this)) { |
| 112 | + var thisHeight = $(this).outerHeight(); |
| 113 | + if (options.forcePlaceholderSize) { |
| 114 | + placeholder.height(draggingHeight); |
| 115 | + } |
| 116 | + |
| 117 | + // Check if $(this) is bigger than the draggable. If it is, we have to define a dead zone to prevent flickering |
| 118 | + if (thisHeight > draggingHeight) { |
| 119 | + // Dead zone? |
| 120 | + var deadZone = thisHeight - draggingHeight, offsetTop = $(this).offset().top; |
| 121 | + if (placeholder.index() < $(this).index() && e.originalEvent.pageY < offsetTop + deadZone) { |
| 122 | + return false; |
| 123 | + } |
| 124 | + else if (placeholder.index() > $(this).index() && e.originalEvent.pageY > offsetTop + thisHeight - deadZone) { |
| 125 | + return false; |
| 126 | + } |
| 127 | + } |
| 128 | + |
| 129 | + dragging.hide(); |
| 130 | + $(this)[placeholder.index() < $(this).index() ? 'after' : 'before'](placeholder); |
| 131 | + placeholders.not(placeholder).detach(); |
| 132 | + } else if (!placeholders.is(this) && !$(this).children(options.items).length) { |
| 133 | + placeholders.detach(); |
| 134 | + $(this).append(placeholder); |
| 135 | + } |
| 136 | + return false; |
| 137 | + }); |
| 138 | + }); |
| 139 | + }; |
| 140 | +})(jQuery); |
0 commit comments