PageSourceSearch

https://ma.moscowpartners.com/Serenity.Assets/Scripts/sortable.js?v=BBvydRU72CWAGeMpFpM-_Q

js moscowpartners.com collected 2026-10-07 15:16:43 UTC 29,407 bytes, 1,271 lines download raw bytes

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

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.