PageSourceSearch

https://rinyo.org/js/Sortable.js?v=c2_Qfyp0CMa-b4Uy2GH08KdJ-hjnxGck6AZ6v2WXJG4

js rinyo.org collected 2026-10-02 03:33:08 UTC 49,423 bytes, 1,491 lines download raw bytes

1/**!
2 * Sortable
3 * @author	RubaXa   <[email protected]>
4 * @license MIT
5 */
6
7(function sortableModule(factory) {
8    "use strict";
9
10    if (typeof define === "function" && define.amd) {
11        define(factory);
12    }
13    else if (typeof module != "undefined" && typeof module.exports != "undefined") {
14        module.exports = factory();
15    }
16    else {
17        /* jshint sub:true */
18        window["Sortable"] = factory();
19    }
20})(function sortableFactory() {
21    "use strict";
22
23    if (typeof window == "undefined" || !window.document) {
24        return function sortableError() {
25            throw new Error("Sortable.js requires a window with a document");
26        };
27    }
28
29    var dragEl,
30        parentEl,
31        ghostEl,
32        cloneEl,
33        rootEl,
34        nextEl,
35        lastDownEl,
36
37        scrollEl,
38        scrollParentEl,
39        scrollCustomFn,
40
41        lastEl,
42        lastCSS,
43        lastParentCSS,
44
45        oldIndex,
46        newIndex,
47
48        activeGroup,
49        putSortable,
50
51        autoScroll = {},
52
53        tapEvt,
54        touchEvt,
55
56        moved,
57
58        /** @const */
59        R_SPACE = /\s+/g,
60        R_FLOAT = /left|right|inline/,
61
62        expando = 'Sortable' + (new Date).getTime(),
63
64        win = window,
65        document = win.document,
66        parseInt = win.parseInt,
67
68        $ = win.jQuery || win.Zepto,
69        Polymer = win.Polymer,
70
71        captureMode = false,
72
73        supportDraggable = !!('draggable' in document.createElement('div')),
74        supportCssPointerEvents = (function (el) {
75            // false when IE11
76            if (!!navigator.userAgent.match(/Trident.*rv[ :]?11\./)) {
77                return false;
78            }
79            el = document.createElement('x');
80            el.style.cssText = 'pointer-events:auto';
81            return el.style.pointerEvents === 'auto';
82        })(),
83
84        _silent = false,
85
86        abs = Math.abs,
87        min = Math.min,
88
89        savedInputChecked = [],
90        touchDragOverListeners = [],
91
92        _autoScroll = _throttle(function (/**Event*/evt, /**Object*/options, /**HTMLElement*/rootEl) {
93            // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
94            if (rootEl && options.scroll) {
95                var _this = rootEl[expando],
96                    el,
97                    rect,
98                    sens = options.scrollSensitivity,
99                    speed = options.scrollSpeed,
100
101                    x = evt.clientX,
102                    y = evt.clientY,
103
104                    winWidth = window.innerWidth,
105                    winHeight = window.innerHeight,
106
107                    vx,
108                    vy,
109
110                    scrollOffsetX,
111                    scrollOffsetY
112                    ;
113
114                // Delect scrollEl
115                if (scrollParentEl !== rootEl) {
116                    scrollEl = options.scroll;
117                    scrollParentEl = rootEl;
118                    scrollCustomFn = options.scrollFn;
119
120                    if (scrollEl === true) {
121                        scrollEl = rootEl;
122
123                        do {
124                            if ((scrollEl.offsetWidth < scrollEl.scrollWidth) ||
125                                (scrollEl.offsetHeight < scrollEl.scrollHeight)
126                            ) {
127                                break;
128                            }
129                            /* jshint boss:true */
130                        } while (scrollEl = scrollEl.parentNode);
131                    }
132                }
133
134                if (scrollEl) {
135                    el = scrollEl;
136                    rect = scrollEl.getBoundingClientRect();
137                    vx = (abs(rect.right - x) <= sens) - (abs(rect.left - x) <= sens);
138                    vy = (abs(rect.bottom - y) <= sens) - (abs(rect.top - y) <= sens);
139                }
140
141
142                if (!(vx || vy)) {
143                    vx = (winWidth - x <= sens) - (x <= sens);
144                    vy = (winHeight - y <= sens) - (y <= sens);
145
146                    /* jshint expr:true */
147                    (vx || vy) && (el = win);
148                }
149
150
151                if (autoScroll.vx !== vx || autoScroll.vy !== vy || autoScroll.el !== el) {
152                    autoScroll.el = el;
153                    autoScroll.vx = vx;
154                    autoScroll.vy = vy;
155
156                    clearInterval(autoScroll.pid);
157
158                    if (el) {
159                        autoScroll.pid = setInterval(function () {
160                            scrollOffsetY = vy ? vy * speed : 0;
161                            scrollOffsetX = vx ? vx * speed : 0;
162
163                            if ('function' === typeof (scrollCustomFn)) {
164                                return scrollCustomFn.call(_this, scrollOffsetX, scrollOffsetY, evt);
165                            }
166
167                            if (el === win) {
168                                win.scrollTo(win.pageXOffset + scrollOffsetX, win.pageYOffset + scrollOffsetY);
169                            } else {
170                                el.scrollTop += scrollOffsetY;
171                                el.scrollLeft += scrollOffsetX;
172                            }
173                        }, 24);
174                    }
175                }
176            }
177        }, 30),
178
179        _prepareGroup = function (options) {
180            function toFn(value, pull) {
181                if (value === void 0 || value === true) {
182                    value = group.name;
183                }
184
185                if (typeof value === 'function') {
186                    return value;
187                } else {
188                    return function (to, from) {
189                        var fromGroup = from.options.group.name;
190
191                        return pull
192                            ? value
193                            : value && (value.join
194                                ? value.indexOf(fromGroup) > -1
195                                : (fromGroup == value)
196                            );
197                    };
198                }
199            }
200
201            var group = {};
202            var originalGroup = options.group;
203
204            if (!originalGroup || typeof originalGroup != 'object') {
205                originalGroup = { name: originalGroup };
206            }
207
208            group.name = originalGroup.name;
209            group.checkPull = toFn(originalGroup.pull, true);
210            group.checkPut = toFn(originalGroup.put);
211            group.revertClone = originalGroup.revertClone;
212
213            options.group = group;
214        }
215        ;
216
217
218	/**
219	 * @class  Sortable
220	 * @param  {HTMLElement}  el
221	 * @param  {Object}       [options]
222	 */
223    function Sortable(el, options) {
224        if (!(el && el.nodeType && el.nodeType === 1)) {
225            throw 'Sortable: `el` must be HTMLElement, and not ' + {}.toString.call(el);
226        }
227
228        this.el = el; // root element
229        this.options = options = _extend({}, options);
230
231
232        // Export instance
233        el[expando] = this;
234
235        // Default options
236        var defaults = {
237            group: Math.random(),
238            sort: true,
239            disabled: false,
240            store: null,
241            handle: null,
242            scroll: true,
243            scrollSensitivity: 30,
244            scrollSpeed: 10,
245            draggable: /[uo]l/i.test(el.nodeName) ? 'li' : '>*',
246            ghostClass: 'sortable-ghost',
247            chosenClass: 'sortable-chosen',
248            dragClass: 'sortable-drag',
249            ignore: 'a, img',
250            filter: null,
251            preventOnFilter: true,
252            animation: 0,
253            setData: function (dataTransfer, dragEl) {
254                dataTransfer.setData('Text', dragEl.textContent);
255            },
256            dropBubble: false,
257            dragoverBubble: false,
258            dataIdAttr: 'data-id',
259            delay: 0,
260            forceFallback: false,
261            fallbackClass: 'sortable-fallback',
262            fallbackOnBody: false,
263            fallbackTolerance: 0,
264            fallbackOffset: { x: 0, y: 0 }
265        };
266
267
268        // Set default options
269        for (var name in defaults) {
270            !(name in options) && (options[name] = defaults[name]);
271        }
272
273        _prepareGroup(options);
274
275        // Bind all private methods
276        for (var fn in this) {
277            if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
278                this[fn] = this[fn].bind(this);
279            }
280        }
281
282        // Setup drag mode
283        this.nativeDraggable = options.forceFallback ? false : supportDraggable;
284
285        // Bind events
286        _on(el, 'mousedown', this._onTapStart);
287        _on(el, 'touchstart', this._onTapStart);
288        _on(el, 'pointerdown', this._onTapStart);
289
290        if (this.nativeDraggable) {
291            _on(el, 'dragover', this);
292            _on(el, 'dragenter', this);
293        }
294
295        touchDragOverListeners.push(this._onDragOver);
296
297        // Restore sorting
298        options.store && this.sort(options.store.get(this));
299    }
300
301
302    Sortable.prototype = /** @lends Sortable.prototype */ {
303        constructor: Sortable,
304
305        _onTapStart: function (/** Event|TouchEvent */evt) {
306            var _this = this,
307                el = this.el,
308                options = this.options,
309                preventOnFilter = options.preventOnFilter,
310                type = evt.type,
311                touch = evt.touches && evt.touches[0],
312                target = (touch || evt).target,
313                originalTarget = evt.target.shadowRoot && (evt.path && evt.path[0]) || target,
314                filter = options.filter,
315                startIndex;
316
317            _saveInputCheckedState(el);
318
319
320            // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group.
321            if (dragEl) {
322                return;
323            }
324
325            if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) {
326                return; // only left button or enabled
327            }
328
329
330            target = _closest(target, options.draggable, el);
331
332            if (!target) {
333                return;
334            }
335
336            if (lastDownEl === target) {
337                // Ignoring duplicate `down`
338                return;
339            }
340
341            // Get the index of the dragged element within its parent
342            startIndex = _index(target, options.draggable);
343
344            // Check filter
345            if (typeof filter === 'function') {
346                if (filter.call(this, evt, target, this)) {
347                    _dispatchEvent(_this, originalTarget, 'filter', target, el, startIndex);
348                    preventOnFilter && evt.preventDefault();
349                    return; // cancel dnd
350                }
351            }
352            else if (filter) {
353                filter = filter.split(',').some(function (criteria) {
354                    criteria = _closest(originalTarget, criteria.trim(), el);
355
356                    if (criteria) {
357                        _dispatchEvent(_this, criteria, 'filter', target, el, startIndex);
358                        return true;
359                    }
360                });
361
362                if (filter) {
363                    preventOnFilter && evt.preventDefault();
364                    return; // cancel dnd
365                }
366            }
367
368            if (options.handle && !_closest(originalTarget, options.handle, el)) {
369                return;
370            }
371
372            // Prepare `dragstart`
373            this._prepareDragStart(evt, touch, target, startIndex);
374        },
375
376        _prepareDragStart: function (/** Event */evt, /** Touch */touch, /** HTMLElement */target, /** Number */startIndex) {
377            var _this = this,
378                el = _this.el,
379                options = _this.options,
380                ownerDocument = el.ownerDocument,
381                dragStartFn;
382
383            if (target && !dragEl && (target.parentNode === el)) {
384                tapEvt = evt;
385
386                rootEl = el;
387                dragEl = target;
388                parentEl = dragEl.parentNode;
389                nextEl = dragEl.nextSibling;
390                lastDownEl = target;
391                activeGroup = options.group;
392                oldIndex = startIndex;
393
394                this._lastX = (touch || evt).clientX;
395                this._lastY = (touch || evt).clientY;
396
397                dragEl.style['will-change'] = 'transform';
398
399                dragStartFn = function () {
400                    // Delayed drag has been triggered
401                    // we can re-enable the events: touchmove/mousemove
402                    _this._disableDelayedDrag();
403
404                    // Make the element draggable
405                    dragEl.draggable = _this.nativeDraggable;
406
407                    // Chosen item
408                    _toggleClass(dragEl, options.chosenClass, true);
409
410                    // Bind the events: dragstart/dragend
411                    _this._triggerDragStart(evt, touch);
412
413                    // Drag start event
414                    _dispatchEvent(_this, rootEl, 'choose', dragEl, rootEl, oldIndex);
415                };
416
417                // Disable "draggable"
418                options.ignore.split(',').forEach(function (criteria) {
419                    _find(dragEl, criteria.trim(), _disableDraggable);
420                });
421
422                _on(ownerDocument, 'mouseup', _this._onDrop);
423                _on(ownerDocument, 'touchend', _this._onDrop);
424                _on(ownerDocument, 'touchcancel', _this._onDrop);
425                _on(ownerDocument, 'pointercancel', _this._onDrop);
426                _on(ownerDocument, 'selectstart', _this);
427
428                if (options.delay) {
429                    // If the user moves the pointer or let go the click or touch
430                    // before the delay has been reached:
431                    // disable the delayed drag
432                    _on(ownerDocument, 'mouseup', _this._disableDelayedDrag);
433                    _on(ownerDocument, 'touchend', _this._disableDelayedDrag);
434                    _on(ownerDocument, 'touchcancel', _this._disableDelayedDrag);
435                    _on(ownerDocument, 'mousemove', _this._disableDelayedDrag);
436                    _on(ownerDocument, 'touchmove', _this._disableDelayedDrag);
437                    _on(ownerDocument, 'pointermove', _this._disableDelayedDrag);
438
439                    _this._dragStartTimer = setTimeout(dragStartFn, options.delay);
440                } else {
441                    dragStartFn();
442                }
443
444
445            }
446        },
447
448        _disableDelayedDrag: function () {
449            var ownerDocument = this.el.ownerDocument;
450
451            clearTimeout(this._dragStartTimer);
452            _off(ownerDocument, 'mouseup', this._disableDelayedDrag);
453            _off(ownerDocument, 'touchend', this._disableDelayedDrag);
454            _off(ownerDocument, 'touchcancel', this._disableDelayedDrag);
455            _off(ownerDocument, 'mousemove', this._disableDelayedDrag);
456            _off(ownerDocument, 'touchmove', this._disableDelayedDrag);
457            _off(ownerDocument, 'pointermove', this._disableDelayedDrag);
458        },
459
460        _triggerDragStart: function (/** Event */evt, /** Touch */touch) {
461            touch = touch || (evt.pointerType == 'touch' ? evt : null);
462
463            if (touch) {
464                // Touch device support
465                tapEvt = {
466                    target: dragEl,
467                    clientX: touch.clientX,
468                    clientY: touch.clientY
469                };
470
471                this._onDragStart(tapEvt, 'touch');
472            }
473            else if (!this.nativeDraggable) {
474                this._onDragStart(tapEvt, true);
475            }
476            else {
477                _on(dragEl, 'dragend', this);
478                _on(rootEl, 'dragstart', this._onDragStart);
479            }
480
481            try {
482                if (document.selection) {
483                    // Timeout neccessary for IE9
484                    setTimeout(function () {
485                        document.selection.empty();
486                    });
487                } else {
488                    window.getSelection().removeAllRanges();
489                }
490            } catch (err) {
491            }
492        },
493
494        _dragStarted: function () {
495            if (rootEl && dragEl) {
496                var options = this.options;
497
498                // Apply effect
499                _toggleClass(dragEl, options.ghostClass, true);
500                _toggleClass(dragEl, options.dragClass, false);
501
502                Sortable.active = this;
503
504                // Drag start event
505                _dispatchEvent(this, rootEl, 'start', dragEl, rootEl, oldIndex);
506            } else {
507                this._nulling();
508            }
509        },
510
511        _emulateDragOver: function () {
512            if (touchEvt) {
513                if (this._lastX === touchEvt.clientX && this._lastY === touchEvt.clientY) {
514                    return;
515                }
516
517                this._lastX = touchEvt.clientX;
518                this._lastY = touchEvt.clientY;
519
520                if (!supportCssPointerEvents) {
521                    _css(ghostEl, 'display', 'none');
522                }
523
524                var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY),
525                    parent = target,
526                    i = touchDragOverListeners.length;
527
528                if (parent) {
529                    do {
530                        if (parent[expando]) {
531                            while (i--) {
532                                touchDragOverListeners[i]({
533                                    clientX: touchEvt.clientX,
534                                    clientY: touchEvt.clientY,
535                                    target: target,
536                                    rootEl: parent
537                                });
538                            }
539
540                            break;
541                        }
542
543                        target = parent; // store last element
544                    }
545                    /* jshint boss:true */
546                    while (parent = parent.parentNode);
547                }
548
549                if (!supportCssPointerEvents) {
550                    _css(ghostEl, 'display', '');
551                }
552            }
553        },
554
555
556        _onTouchMove: function (/**TouchEvent*/evt) {
557            if (tapEvt) {
558                var options = this.options,
559                    fallbackTolerance = options.fallbackTolerance,
560                    fallbackOffset = options.fallbackOffset,
561                    touch = evt.touches ? evt.touches[0] : evt,
562                    dx = (touch.clientX - tapEvt.clientX) + fallbackOffset.x,
563                    dy = (touch.clientY - tapEvt.clientY) + fallbackOffset.y,
564                    translate3d = evt.touches ? 'translate3d(' + dx + 'px,' + dy + 'px,0)' : 'translate(' + dx + 'px,' + dy + 'px)';
565
566                // only set the status to dragging, when we are actually dragging
567                if (!Sortable.active) {
568                    if (fallbackTolerance &&
569                        min(abs(touch.clientX - this._lastX), abs(touch.clientY - this._lastY)) < fallbackTolerance
570                    ) {
571                        return;
572                    }
573
574                    this._dragStarted();
575                }
576
577                // as well as creating the ghost element on the document body
578                this._appendGhost();
579
580                moved = true;
581                touchEvt = touch;
582
583                _css(ghostEl, 'webkitTransform', translate3d);
584                _css(ghostEl, 'mozTransform', translate3d);
585                _css(ghostEl, 'msTransform', translate3d);
586                _css(ghostEl, 'transform', translate3d);
587
588                evt.preventDefault();
589            }
590        },
591
592        _appendGhost: function () {
593            if (!ghostEl) {
594                var rect = dragEl.getBoundingClientRect(),
595                    css = _css(dragEl),
596                    options = this.options,
597                    ghostRect;
598
599                ghostEl = dragEl.cloneNode(true);
600
601                _toggleClass(ghostEl, options.ghostClass, false);
602                _toggleClass(ghostEl, options.fallbackClass, true);
603                _toggleClass(ghostEl, options.dragClass, true);
604
605                _css(ghostEl, 'top', rect.top - parseInt(css.marginTop, 10));
606                _css(ghostEl, 'left', rect.left - parseInt(css.marginLeft, 10));
607                _css(ghostEl, 'width', rect.width);
608                _css(ghostEl, 'height', rect.height);
609                _css(ghostEl, 'opacity', '0.8');
610                _css(ghostEl, 'position', 'fixed');
611                _css(ghostEl, 'zIndex', '100000');
612                _css(ghostEl, 'pointerEvents', 'none');
613
614                options.fallbackOnBody && document.body.appendChild(ghostEl) || rootEl.appendChild(ghostEl);
615
616                // Fixing dimensions.
617                ghostRect = ghostEl.getBoundingClientRect();
618                _css(ghostEl, 'width', rect.width * 2 - ghostRect.width);
619                _css(ghostEl, 'height', rect.height * 2 - ghostRect.height);
620            }
621        },
622
623        _onDragStart: function (/**Event*/evt, /**boolean*/useFallback) {
624            var dataTransfer = evt.dataTransfer,
625                options = this.options;
626
627            this._offUpEvents();
628
629            if (activeGroup.checkPull(this, this, dragEl, evt)) {
630                cloneEl = _clone(dragEl);
631
632                cloneEl.draggable = false;
633                cloneEl.style['will-change'] = '';
634
635                _css(cloneEl, 'display', 'none');
636                _toggleClass(cloneEl, this.options.chosenClass, false);
637
638                rootEl.insertBefore(cloneEl, dragEl);
639                _dispatchEvent(this, rootEl, 'clone', dragEl);
640            }
641
642            _toggleClass(dragEl, options.dragClass, true);
643
644            if (useFallback) {
645                if (useFallback === 'touch') {
646                    // Bind touch events
647                    _on(document, 'touchmove', this._onTouchMove);
648                    _on(document, 'touchend', this._onDrop);
649                    _on(document, 'touchcancel', this._onDrop);
650                    _on(document, 'pointermove', this._onTouchMove);
651                    _on(document, 'pointerup', this._onDrop);
652                } else {
653                    // Old brwoser
654                    _on(document, 'mousemove', this._onTouchMove);
655                    _on(document, 'mouseup', this._onDrop);
656                }
657
658                this._loopId = setInterval(this._emulateDragOver, 50);
659            }
660            else {
661                if (dataTransfer) {
662                    dataTransfer.effectAllowed = 'move';
663                    options.setData && options.setData.call(this, dataTransfer, dragEl);
664                }
665
666                _on(document, 'drop', this);
667                setTimeout(this._dragStarted, 0);
668            }
669        },
670
671        _onDragOver: function (/**Event*/evt) {
672            var el = this.el,
673                target,
674                dragRect,
675                targetRect,
676                revert,
677                options = this.options,
678                group = options.group,
679                activeSortable = Sortable.active,
680                isOwner = (activeGroup === group),
681                isMovingBetweenSortable = false,
682                canSort = options.sort;
683
684            if (evt.preventDefault !== void 0) {
685                evt.preventDefault();
686                !options.dragoverBubble && evt.stopPropagation();
687            }
688
689            if (dragEl.animated) {
690                return;
691            }
692
693            moved = true;
694
695            if (activeSortable && !options.disabled &&
696                (isOwner
697                    ? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list
698                    : (
699                        putSortable === this ||
700                        (
701                            (activeSortable.lastPullMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) &&
702                            group.checkPut(this, activeSortable, dragEl, evt)
703                        )
704                    )
705                ) &&
706                (evt.rootEl === void 0 || evt.rootEl === this.el) // touch fallback
707            ) {
708                // Smart auto-scrolling
709                _autoScroll(evt, options, this.el);
710
711                if (_silent) {
712                    return;
713                }
714
715                target = _closest(evt.target, options.draggable, el);
716                dragRect = dragEl.getBoundingClientRect();
717
718                if (putSortable !== this) {
719                    putSortable = this;
720                    isMovingBetweenSortable = true;
721                }
722
723                if (revert) {
724                    _cloneHide(activeSortable, true);
725                    parentEl = rootEl; // actualization
726
727                    if (cloneEl || nextEl) {
728                        rootEl.insertBefore(dragEl, cloneEl || nextEl);
729                    }
730                    else if (!canSort) {
731                        rootEl.appendChild(dragEl);
732                    }
733
734                    return;
735                }
736
737
738                if ((el.children.length === 0) || (el.children[0] === ghostEl) ||
739                    (el === evt.target) && (_ghostIsLast(el, evt))
740                ) {
741                    //assign target only if condition is true
742                    if (el.children.length !== 0 && el.children[0] !== ghostEl && el === evt.target) {
743                        target = el.lastElementChild;
744                    }
745
746                    if (target) {
747                        if (target.animated) {
748                            return;
749                        }
750
751                        targetRect = target.getBoundingClientRect();
752                    }
753
754                    _cloneHide(activeSortable, isOwner);
755
756                    if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt) !== false) {
757                        if (!dragEl.contains(el)) {
758                            el.appendChild(dragEl);
759                            parentEl = el; // actualization
760                        }
761
762                        this._animate(dragRect, dragEl);
763                        target && this._animate(targetRect, target);
764                    }
765                }
766                else if (target && !target.animated && target !== dragEl && (target.parentNode[expando] !== void 0)) {
767                    if (lastEl !== target) {
768                        lastEl = target;
769                        lastCSS = _css(target);
770                        lastParentCSS = _css(target.parentNode);
771                    }
772
773                    targetRect = target.getBoundingClientRect();
774
775                    var width = targetRect.right - targetRect.left,
776                        height = targetRect.bottom - targetRect.top,
777                        floating = R_FLOAT.test(lastCSS.cssFloat + lastCSS.display)
778                            || (lastParentCSS.display == 'flex' && lastParentCSS['flex-direction'].indexOf('row') === 0),
779                        isWide = (target.offsetWidth > dragEl.offsetWidth),
780                        isLong = (target.offsetHeight > dragEl.offsetHeight),
781                        halfway = (floating ? (evt.clientX - targetRect.left) / width : (evt.clientY - targetRect.top) / height) > 0.5,
782                        nextSibling = target.nextElementSibling,
783                        after = false
784                        ;
785
786                    if (floating) {
787                        var elTop = dragEl.offsetTop,
788                            tgTop = target.offsetTop;
789
790                        if (elTop === tgTop) {
791                            after = (target.previousElementSibling === dragEl) && !isWide || halfway && isWide;
792                        }
793                        else if (target.previousElementSibling === dragEl || dragEl.previousElementSibling === target) {
794                            after = (evt.clientY - targetRect.top) / height > 0.5;
795                        } else {
796                            after = tgTop > elTop;
797                        }
798                    } else if (!isMovingBetweenSortable) {
799                        after = (nextSibling !== dragEl) && !isLong || halfway && isLong;
800                    }
801
802                    var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after);
803
804                    if (moveVector !== false) {
805                        if (moveVector === 1 || moveVector === -1) {
806                            after = (moveVector === 1);
807                        }
808
809                        _silent = true;
810                        setTimeout(_unsilent, 30);
811
812                        _cloneHide(activeSortable, isOwner);
813
814                        if (!dragEl.contains(el)) {
815                            if (after && !nextSibling) {
816                                el.appendChild(dragEl);
817                            } else {
818                                target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
819                            }
820                        }
821
822                        parentEl = dragEl.parentNode; // actualization
823
824                        this._animate(dragRect, dragEl);
825                        this._animate(targetRect, target);
826                    }
827                }
828            }
829        },
830
831        _animate: function (prevRect, target) {
832            var ms = this.options.animation;
833
834            if (ms) {
835                var currentRect = target.getBoundingClientRect();
836
837                if (prevRect.nodeType === 1) {
838                    prevRect = prevRect.getBoundingClientRect();
839                }
840
841                _css(target, 'transition', 'none');
842                _css(target, 'transform', 'translate3d('
843                    + (prevRect.left - currentRect.left) + 'px,'
844                    + (prevRect.top - currentRect.top) + 'px,0)'
845                );
846
847                target.offsetWidth; // repaint
848
849                _css(target, 'transition', 'all ' + ms + 'ms');
850                _css(target, 'transform', 'translate3d(0,0,0)');
851
852                clearTimeout(target.animated);
853                target.animated = setTimeout(function () {
854                    _css(target, 'transition', '');
855                    _css(target, 'transform', '');
856                    target.animated = false;
857                }, ms);
858            }
859        },
860
861        _offUpEvents: function () {
862            var ownerDocument = this.el.ownerDocument;
863
864            _off(document, 'touchmove', this._onTouchMove);
865            _off(document, 'pointermove', this._onTouchMove);
866            _off(ownerDocument, 'mouseup', this._onDrop);
867            _off(ownerDocument, 'touchend', this._onDrop);
868            _off(ownerDocument, 'pointerup', this._onDrop);
869            _off(ownerDocument, 'touchcancel', this._onDrop);
870            _off(ownerDocument, 'pointercancel', this._onDrop);
871            _off(ownerDocument, 'selectstart', this);
872        },
873
874        _onDrop: function (/**Event*/evt) {
875            var el = this.el,
876                options = this.options;
877
878            clearInterval(this._loopId);
879            clearInterval(autoScroll.pid);
880            clearTimeout(this._dragStartTimer);
881
882            // Unbind events
883            _off(document, 'mousemove', this._onTouchMove);
884
885            if (this.nativeDraggable) {
886                _off(document, 'drop', this);
887                _off(el, 'dragstart', this._onDragStart);
888            }
889
890            this._offUpEvents();
891
892            if (evt) {
893                if (moved) {
894                    evt.preventDefault();
895                    !options.dropBubble && evt.stopPropagation();
896                }
897
898                ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl);
899
900                if (rootEl === parentEl || Sortable.active.lastPullMode !== 'clone') {
901                    // Remove clone
902                    cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl);
903                }
904
905                if (dragEl) {
906                    if (this.nativeDraggable) {
907                        _off(dragEl, 'dragend', this);
908                    }
909
910                    _disableDraggable(dragEl);
911                    dragEl.style['will-change'] = '';
912
913                    // Remove class's
914                    _toggleClass(dragEl, this.options.ghostClass, false);
915                    _toggleClass(dragEl, this.options.chosenClass, false);
916
917                    // Drag stop event
918                    _dispatchEvent(this, rootEl, 'unchoose', dragEl, rootEl, oldIndex);
919
920                    if (rootEl !== parentEl) {
921                        newIndex = _index(dragEl, options.draggable);
922
923                        if (newIndex >= 0) {
924                            // Add event
925                            _dispatchEvent(null, parentEl, 'add', dragEl, rootEl, oldIndex, newIndex);
926
927                            // Remove event
928                            _dispatchEvent(this, rootEl, 'remove', dragEl, rootEl, oldIndex, newIndex);
929
930                            // drag from one list and drop into another
931                            _dispatchEvent(null, parentEl, 'sort', dragEl, rootEl, oldIndex, newIndex);
932                            _dispatchEvent(this, rootEl, 'sort', dragEl, rootEl, oldIndex, newIndex);
933                        }
934                    }
935                    else {
936                        if (dragEl.nextSibling !== nextEl) {
937                            // Get the index of the dragged element within its parent
938                            newIndex = _index(dragEl, options.draggable);
939
940                            if (newIndex >= 0) {
941                                // drag & drop within the same list
942                                _dispatchEvent(this, rootEl, 'update', dragEl, rootEl, oldIndex, newIndex);
943                                _dispatchEvent(this, rootEl, 'sort', dragEl, rootEl, oldIndex, newIndex);
944                            }
945                        }
946                    }
947
948                    if (Sortable.active) {
949                        /* jshint eqnull:true */
950                        if (newIndex == null || newIndex === -1) {
951                            newIndex = oldIndex;
952                        }
953
954                        _dispatchEvent(this, rootEl, 'end', dragEl, rootEl, oldIndex, newIndex);
955
956                        // Save sorting
957                        this.save();
958                    }
959                }
960
961            }
962
963            this._nulling();
964        },
965
966        _nulling: function () {
967            rootEl =
968                dragEl =
969                parentEl =
970                ghostEl =
971                nextEl =
972                cloneEl =
973                lastDownEl =
974
975                scrollEl =
976                scrollParentEl =
977
978                tapEvt =
979                touchEvt =
980
981                moved =
982                newIndex =
983
984                lastEl =
985                lastCSS =
986
987                putSortable =
988                activeGroup =
989                Sortable.active = null;
990
991            savedInputChecked.forEach(function (el) {
992                el.checked = true;
993            });
994            savedInputChecked.length = 0;
995        },
996
997        handleEvent: function (/**Event*/evt) {
998            switch (evt.type) {
999                case 'drop':
1000                case 'dragend':
1001                    this._onDrop(evt);
1002                    break;
1003
1004                case 'dragover':
1005                case 'dragenter':
1006                    if (dragEl) {
1007                        this._onDragOver(evt);
1008                        _globalDragOver(evt);
1009                    }
1010                    break;
1011
1012                case 'selectstart':
1013                    evt.preventDefault();
1014                    break;
1015            }
1016        },
1017
1018
1019		/**
1020		 * Serializes the item into an array of string.
1021		 * @returns {String[]}
1022		 */
1023        toArray: function () {
1024            var order = [],
1025                el,
1026                children = this.el.children,
1027                i = 0,
1028                n = children.length,
1029                options = this.options;
1030
1031            for (; i < n; i++) {
1032                el = children[i];
1033                if (_closest(el, options.draggable, this.el)) {
1034                    order.push(el.getAttribute(options.dataIdAttr) || _generateId(el));
1035                }
1036            }
1037
1038            return order;
1039        },
1040
1041
1042		/**
1043		 * Sorts the elements according to the array.
1044		 * @param  {String[]}  order  order of the items
1045		 */
1046        sort: function (order) {
1047            var items = {}, rootEl = this.el;
1048
1049            this.toArray().forEach(function (id, i) {
1050                var el = rootEl.children[i];
1051
1052                if (_closest(el, this.options.draggable, rootEl)) {
1053                    items[id] = el;
1054                }
1055            }, this);
1056
1057            order.forEach(function (id) {
1058                if (items[id]) {
1059                    rootEl.removeChild(items[id]);
1060                    rootEl.appendChild(items[id]);
1061                }
1062            });
1063        },
1064
1065
1066		/**
1067		 * Save the current sorting
1068		 */
1069        save: function () {
1070            var store = this.options.store;
1071            store && store.set(this);
1072        },
1073
1074
1075		/**
1076		 * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
1077		 * @param   {HTMLElement}  el
1078		 * @param   {String}       [selector]  default: `options.draggable`
1079		 * @returns {HTMLElement|null}
1080		 */
1081        closest: function (el, selector) {
1082            return _closest(el, selector || this.options.draggable, this.el);
1083        },
1084
1085
1086		/**
1087		 * Set/get option
1088		 * @param   {string} name
1089		 * @param   {*}      [value]
1090		 * @returns {*}
1091		 */
1092        option: function (name, value) {
1093            var options = this.options;
1094
1095            if (value === void 0) {
1096                return options[name];
1097            } else {
1098                options[name] = value;
1099
1100                if (name === 'group') {
1101                    _prepareGroup(options);
1102                }
1103            }
1104        },
1105
1106
1107		/**
1108		 * Destroy
1109		 */
1110        destroy: function () {
1111            var el = this.el;
1112
1113            el[expando] = null;
1114
1115            _off(el, 'mousedown', this._onTapStart);
1116            _off(el, 'touchstart', this._onTapStart);
1117            _off(el, 'pointerdown', this._onTapStart);
1118
1119            if (this.nativeDraggable) {
1120                _off(el, 'dragover', this);
1121                _off(el, 'dragenter', this);
1122            }
1123
1124            // Remove draggable attributes
1125            Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {
1126                el.removeAttribute('draggable');
1127            });
1128
1129            touchDragOverListeners.splice(touchDragOverListeners.indexOf(this._onDragOver), 1);
1130
1131            this._onDrop();
1132
1133            this.el = el = null;
1134        }
1135    };
1136
1137
1138    function _cloneHide(sortable, state) {
1139        if (sortable.lastPullMode !== 'clone') {
1140            state = true;
1141        }
1142
1143        if (cloneEl && (cloneEl.state !== state)) {
1144            _css(cloneEl, 'display', state ? 'none' : '');
1145
1146            if (!state) {
1147                if (cloneEl.state) {
1148                    if (sortable.options.group.revertClone) {
1149                        rootEl.insertBefore(cloneEl, nextEl);
1150                        sortable._animate(dragEl, cloneEl);
1151                    } else {
1152                        rootEl.insertBefore(cloneEl, dragEl);
1153                    }
1154                }
1155            }
1156
1157            cloneEl.state = state;
1158        }
1159    }
1160
1161
1162    function _closest(/**HTMLElement*/el, /**String*/selector, /**HTMLElement*/ctx) {
1163        if (el) {
1164            ctx = ctx || document;
1165
1166            do {
1167                if ((selector === '>*' && el.parentNode === ctx) || _matches(el, selector)) {
1168                    return el;
1169                }
1170                /* jshint boss:true */
1171            } while (el = _getParentOrHost(el));
1172        }
1173
1174        return null;
1175    }
1176
1177
1178    function _getParentOrHost(el) {
1179        var parent = el.host;
1180
1181        return (parent && parent.nodeType) ? parent : el.parentNode;
1182    }
1183
1184
1185    function _globalDragOver(/**Event*/evt) {
1186        if (evt.dataTransfer) {
1187            evt.dataTransfer.dropEffect = 'move';
1188        }
1189        evt.preventDefault();
1190    }
1191
1192
1193    function _on(el, event, fn) {
1194        el.addEventListener(event, fn, captureMode);
1195    }
1196
1197
1198    function _off(el, event, fn) {
1199        el.removeEventListener(event, fn, captureMode);
1200    }
1201
1202
1203    function _toggleClass(el, name, state) {
1204        if (el) {
1205            if (el.classList) {
1206                el.classList[state ? 'add' : 'remove'](name);
1207            }
1208            else {
1209                var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' ');
1210                el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' ');
1211            }
1212        }
1213    }
1214
1215
1216    function _css(el, prop, val) {
1217        var style = el && el.style;
1218
1219        if (style) {
1220            if (val === void 0) {
1221                if (document.defaultView && document.defaultView.getComputedStyle) {
1222                    val = document.defaultView.getComputedStyle(el, '');
1223                }
1224                else if (el.currentStyle) {
1225                    val = el.currentStyle;
1226                }
1227
1228                return prop === void 0 ? val : val[prop];
1229            }
1230            else {
1231                if (!(prop in style)) {
1232                    prop = '-webkit-' + prop;
1233                }
1234
1235                style[prop] = val + (typeof val === 'string' ? '' : 'px');
1236            }
1237        }
1238    }
1239
1240
1241    function _find(ctx, tagName, iterator) {
1242        if (ctx) {
1243            var list = ctx.getElementsByTagName(tagName), i = 0, n = list.length;
1244
1245            if (iterator) {
1246                for (; i < n; i++) {
1247                    iterator(list[i], i);
1248                }
1249            }
1250
1251            return list;
1252        }
1253
1254        return [];
1255    }
1256
1257
1258
1259    function _dispatchEvent(sortable, rootEl, name, targetEl, fromEl, startIndex, newIndex) {
1260        sortable = (sortable || rootEl[expando]);
1261
1262        var evt = document.createEvent('Event'),
1263            options = sortable.options,
1264            onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1);
1265
1266        evt.initEvent(name, true, true);
1267
1268        evt.to = rootEl;
1269        evt.from = fromEl || rootEl;
1270        evt.item = targetEl || rootEl;
1271        evt.clone = cloneEl;
1272
1273        evt.oldIndex = startIndex;
1274        evt.newIndex = newIndex;
1275
1276        rootEl.dispatchEvent(evt);
1277
1278        if (options[onName]) {
1279            options[onName].call(sortable, evt);
1280        }
1281    }
1282
1283
1284    function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvt, willInsertAfter) {
1285        var evt,
1286            sortable = fromEl[expando],
1287            onMoveFn = sortable.options.onMove,
1288            retVal;
1289
1290        evt = document.createEvent('Event');
1291        evt.initEvent('move', true, true);
1292
1293        evt.to = toEl;
1294        evt.from = fromEl;
1295        evt.dragged = dragEl;
1296        evt.draggedRect = dragRect;
1297        evt.related = targetEl || toEl;
1298        evt.relatedRect = targetRect || toEl.getBoundingClientRect();
1299        evt.willInsertAfter = willInsertAfter;
1300
1301        fromEl.dispatchEvent(evt);
1302
1303        if (onMoveFn) {
1304            retVal = onMoveFn.call(sortable, evt, originalEvt);
1305        }
1306
1307        return retVal;
1308    }
1309
1310
1311    function _disableDraggable(el) {
1312        el.draggable = false;
1313    }
1314
1315
1316    function _unsilent() {
1317        _silent = false;
1318    }
1319
1320
1321    /** @returns {HTMLElement|false} */
1322    function _ghostIsLast(el, evt) {
1323        var lastEl = el.lastElementChild,
1324            rect = lastEl.getBoundingClientRect();
1325
1326        // 5 — min delta
1327        // abs — нельзя добавлять, а то глюки при наведении сверху
1328        return (evt.clientY - (rect.top + rect.height) > 5) ||
1329            (evt.clientX - (rect.left + rect.width) > 5);
1330    }
1331
1332
1333	/**
1334	 * Generate id
1335	 * @param   {HTMLElement} el
1336	 * @returns {String}
1337	 * @private
1338	 */
1339    function _generateId(el) {
1340        var str = el.tagName + el.className + el.src + el.href + el.textContent,
1341            i = str.length,
1342            sum = 0;
1343
1344        while (i--) {
1345            sum += str.charCodeAt(i);
1346        }
1347
1348        return sum.toString(36);
1349    }
1350
1351	/**
1352	 * Returns the index of an element within its parent for a selected set of
1353	 * elements
1354	 * @param  {HTMLElement} el
1355	 * @param  {selector} selector
1356	 * @return {number}
1357	 */
1358    function _index(el, selector) {
1359        var index = 0;
1360
1361        if (!el || !el.parentNode) {
1362            return -1;
1363        }
1364
1365        while (el && (el = el.previousElementSibling)) {
1366            if ((el.nodeName.toUpperCase() !== 'TEMPLATE') && (selector === '>*' || _matches(el, selector))) {
1367                index++;
1368            }
1369        }
1370
1371        return index;
1372    }
1373
1374    function _matches(/**HTMLElement*/el, /**String*/selector) {
1375        if (el) {
1376            selector = selector.split('.');
1377
1378            var tag = selector.shift().toUpperCase(),
1379                re = new RegExp('\\s(' + selector.join('|') + ')(?=\\s)', 'g');
1380
1381            return (
1382                (tag === '' || el.nodeName.toUpperCase() == tag) &&
1383                (!selector.length || ((' ' + el.className + ' ').match(re) || []).length == selector.length)
1384            );
1385        }
1386
1387        return false;
1388    }
1389
1390    function _throttle(callback, ms) {
1391        var args, _this;
1392
1393        return function () {
1394            if (args === void 0) {
1395                args = arguments;
1396                _this = this;
1397
1398                setTimeout(function () {
1399                    if (args.length === 1) {
1400                        callback.call(_this, args[0]);
1401                    } else {
1402                        callback.apply(_this, args);
1403                    }
1404
1405                    args = void 0;
1406                }, ms);
1407            }
1408        };
1409    }
1410
1411    function _extend(dst, src) {
1412        if (dst && src) {
1413            for (var key in src) {
1414                if (src.hasOwnProperty(key)) {
1415                    dst[key] = src[key];
1416                }
1417            }
1418        }
1419
1420        return dst;
1421    }
1422
1423    function _clone(el) {
1424        return $
1425            ? $(el).clone(true)[0]
1426            : (Polymer && Polymer.dom
1427                ? Polymer.dom(el).cloneNode(true)
1428                : el.cloneNode(true)
1429            );
1430    }
1431
1432    function _saveInputCheckedState(root) {
1433        var inputs = root.getElementsByTagName('input');
1434        var idx = inputs.length;
1435
1436        while (idx--) {
1437            var el = inputs[idx];
1438            el.checked && savedInputChecked.push(el);
1439        }
1440    }
1441
1442    // Fixed #973: 
1443    _on(document, 'touchmove', function (evt) {
1444        if (Sortable.active) {
1445            evt.preventDefault();
1446        }
1447    });
1448
1449    try {
1450        window.addEventListener('test', null, Object.defineProperty({}, 'passive', {
1451            get: function () {
1452                captureMode = {
1453                    capture: false,
1454                    passive: false
1455                };
1456            }
1457        }));
1458    } catch (err) { }
1459
1460    // Export utils
1461    Sortable.utils = {
1462        on: _on,
1463        off: _off,
1464        css: _css,
1465        find: _find,
1466        is: function (el, selector) {
1467            return !!_closest(el, selector, el);
1468        },
1469        extend: _extend,
1470        throttle: _throttle,
1471        closest: _closest,
1472        toggleClass: _toggleClass,
1473        clone: _clone,
1474        index: _index
1475    };
1476
1477
1478	/**
1479	 * Create sortable instance
1480	 * @param {HTMLElement}  el
1481	 * @param {Object}      [options]
1482	 */
1483    Sortable.create = function (el, options) {
1484        return new Sortable(el, options);
1485    };
1486
1487
1488    // Export
1489    Sortable.version = '1.6.1';
1490    return Sortable;
1491});

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.