Full Code of SortableJS/Sortable for AI

master 031649b81165 cached
64 files
723.9 KB
192.6k tokens
411 symbols
1 requests
Download .txt
Showing preview only (751K chars total). Download the full file or copy to clipboard to get everything.
Repository: SortableJS/Sortable
Branch: master
Commit: 031649b81165
Files: 64
Total size: 723.9 KB

Directory structure:
gitextract_s2mraq4s/

├── .circleci/
│   └── config.yml
├── .editorconfig
├── .github/
│   └── ISSUE_TEMPLATE/
│       ├── bug-report.md
│       ├── custom-template.md
│       └── feature-request.md
├── .gitignore
├── .jshintrc
├── .testcaferc.json
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── Sortable.js
├── babel.config.js
├── bower.json
├── entry/
│   ├── entry-complete.js
│   ├── entry-core.js
│   └── entry-defaults.js
├── index.html
├── modular/
│   ├── sortable.complete.esm.js
│   ├── sortable.core.esm.js
│   └── sortable.esm.js
├── package.json
├── plugins/
│   ├── AutoScroll/
│   │   ├── AutoScroll.js
│   │   ├── README.md
│   │   └── index.js
│   ├── MultiDrag/
│   │   ├── MultiDrag.js
│   │   ├── README.md
│   │   └── index.js
│   ├── OnSpill/
│   │   ├── OnSpill.js
│   │   ├── README.md
│   │   └── index.js
│   ├── README.md
│   └── Swap/
│       ├── README.md
│       ├── Swap.js
│       └── index.js
├── scripts/
│   ├── banner.js
│   ├── build.js
│   ├── esm-build.js
│   ├── minify.js
│   ├── test-compat.js
│   ├── test.js
│   └── umd-build.js
├── src/
│   ├── Animation.js
│   ├── BrowserInfo.js
│   ├── EventDispatcher.js
│   ├── PluginManager.js
│   ├── Sortable.js
│   └── utils.js
├── st/
│   ├── app.js
│   ├── iframe/
│   │   ├── frame.html
│   │   └── index.html
│   ├── prettify/
│   │   ├── prettify.css
│   │   ├── prettify.js
│   │   └── run_prettify.js
│   └── theme.css
└── tests/
    ├── Sortable.compat.test.js
    ├── Sortable.test.js
    ├── dual-list.html
    ├── empty-list.html
    ├── filter.html
    ├── handles.html
    ├── nested.html
    ├── single-list.html
    └── style.css

================================================
FILE CONTENTS
================================================

================================================
FILE: .circleci/config.yml
================================================
version: 2.0
jobs:
  build:
    docker:
      - image: circleci/node:10.16-browsers
    steps:
      - checkout

      - restore_cache:
          keys:
          - v1-dependencies-{{ checksum "package.json" }}
          - v1-dependencies-

      - run: npm install

      - save_cache:
          paths:
            - node_modules
          key: v1-dependencies-{{ checksum "package.json" }}

      - run: npm run build:umd

      - run:
          name: Compatibility Test
          command: |
            if [ -z "$CIRCLE_PR_NUMBER" ];
            then
              npm run test:compat
            fi
      - run: npm run test

      - store_test_results:
          path: /tmp/test-results


================================================
FILE: .editorconfig
================================================
# editorconfig.org
root = true

[*]
indent_style = tab
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false

[*.yml]
indent_style = space


================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: "[bug] "
labels: ""
assignees: ""
---

<!--

PLEASE READ BEFORE POSTING YOUR ISSUE!

If your issue is related to a framework or @types/sortablejs,
please post an issue on it's relevant repository instead:

- Angular
  - 2.0+: https://github.com/SortableJS/angular-sortablejs/issues
  - legacy: https://github.com/SortableJS/angular-legacy-sortablejs/issues
- React
  - ES2015+: https://github.com/SortableJS/react-sortablejs/issues
  - mixin: https://github.com/SortableJS/react-mixin-sortablejs/issues
- Polymer: https://github.com/SortableJS/polymer-sortablejs/issues
- Knockout: https://github.com/SortableJS/knockout-sortablejs/issues
- Meteor: https://github.com/SortableJS/meteor-sortablejs/issues


If it is a bug found from using one of these, please link to the related issue.

-->

**Describe the bug**

<!-- A clear and concise description of what the bug is. -->

**To Reproduce**
Steps to reproduce the behavior:

1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**

<!-- A clear and concise description of what you expected to happen. -->

**Information**

<!-- This is required. Issues without this critical information will be closed. -->

Versions - Look in your `package.json` for this information:
sortablejs = ^x.x.x
@types/sortablejs = ^x.x.x

**Additional context**
Add any other context about the problem here.

**Reproduction**
codesandbox: <your_url_here>

<!--

Providing a codesandbox really helps us understand your issue.
Bugs with codesandboxes attached are likely to be resolved more quickly than others.

Once you've created a public codesandbox, please paste a link in here

Here are some templates to get you started.

- Javascript: https://codesandbox.io/s/sortablejs-javascript-jy3tl?file=/src/index.js
- Typescript: https://codesandbox.io/s/sortablejs-typescript-6it9n?file=/src/index.ts

-->


================================================
FILE: .github/ISSUE_TEMPLATE/custom-template.md
================================================
---
name: Custom issue template
about: Not a feature request or a bug report. Usually questions, queries or concerns
title: ""
labels: ""
assignees: ""
---

**Custom**

<!--

PLEASE READ BEFORE POSTING YOUR ISSUE!

If your issue is related to a framework or @types/sortablejs,
please post an issue on it's relevant repository instead:

- Angular
  - 2.0+: https://github.com/SortableJS/angular-sortablejs/issues
  - legacy: https://github.com/SortableJS/angular-legacy-sortablejs/issues
- React
  - ES2015+: https://github.com/SortableJS/react-sortablejs/issues
  - mixin: https://github.com/SortableJS/react-mixin-sortablejs/issues
- Polymer: https://github.com/SortableJS/polymer-sortablejs/issues
- Knockout: https://github.com/SortableJS/knockout-sortablejs/issues
- Meteor: https://github.com/SortableJS/meteor-sortablejs/issues


If it is a bug found from using one of these, please link to the related issue.

-->

**Reproduction**
codesandbox: <your_url_here>

<!--

Providing a codesandbox really helps us understand your issue.
Bugs with codesandboxes attached are likely to be resolved more quickly than others.

Once you've created a public codesandbox, please paste a link in here

Here are some templates to get you started.

- Javascript: https://codesandbox.io/s/sortablejs-javascript-jy3tl?file=/src/index.js
- Typescript: https://codesandbox.io/s/sortablejs-typescript-6it9n?file=/src/index.ts

-->


================================================
FILE: .github/ISSUE_TEMPLATE/feature-request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: "[feature] "
labels: ""
assignees: ""
---

<!--

PLEASE READ BEFORE POSTING YOUR ISSUE!

If your issue is related to a framework or @types/sortablejs,
please post an issue on it's relevant repository instead:

- Angular
  - 2.0+: https://github.com/SortableJS/angular-sortablejs/issues
  - legacy: https://github.com/SortableJS/angular-legacy-sortablejs/issues
- React
  - ES2015+: https://github.com/SortableJS/react-sortablejs/issues
  - mixin: https://github.com/SortableJS/react-mixin-sortablejs/issues
- Polymer: https://github.com/SortableJS/polymer-sortablejs/issues
- Knockout: https://github.com/SortableJS/knockout-sortablejs/issues
- Meteor: https://github.com/SortableJS/meteor-sortablejs/issues


If it is a bug found from using one of these, please link to the related issue.

-->

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


================================================
FILE: .gitignore
================================================
node_modules
mock.png
.*.sw*
.build*
jquery.fn.*
.idea/


================================================
FILE: .jshintrc
================================================
{
	"strict": false,
	"newcap": false,
	"node": true,
	"expr": true,
	"supernew": true,
	"laxbreak": true,
	"esversion": 9,
	"white": true,
	"globals": {
		"define": true,
		"test": true,
		"expect": true,
		"module": true,
		"asyncTest": true,
		"start": true,
		"ok": true,
		"equal": true,
		"notEqual": true,
		"deepEqual": true,
		"window": true,
		"document": true,
		"performance": true
	}
}


================================================
FILE: .testcaferc.json
================================================
{
	"speed": 0.4,
	"reporter": {
		"name": "xunit",
		"output": "/tmp/test-results/res.xml"
	}
}


================================================
FILE: CONTRIBUTING.md
================================================
# Contribution Guidelines

### Issue

 1. Try [master](https://github.com/SortableJS/Sortable/tree/master/)-branch, perhaps the problem has been solved;
 2. [Use the search](https://github.com/SortableJS/Sortable/search?type=Issues&q=problem), maybe already have an answer;
 3. If not found, create example on [jsbin.com (draft)](https://jsbin.com/kamiwez/edit?html,js,output) and describe the problem.

---

### Pull Request

 1. Only request to merge with the [master](https://github.com/SortableJS/Sortable/tree/master/)-branch.
 2. Only modify source files, **do not commit the resulting build**

### Setup

 1. Fork the repo on [github](https://github.com)
 2. Clone locally
 3. Run `npm i` in the local repo

### Building

 - For development, build the `./Sortable.js` file using the command `npm run build:umd:watch`
 - To build everything and minify it, run `npm run build`
 - Do not commit the resulting builds in any pull request – they will be generated at release


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2019 All contributors to Sortable

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# Sortable &nbsp; [![Financial Contributors on Open Collective](https://opencollective.com/Sortable/all/badge.svg?label=financial+contributors)](https://opencollective.com/Sortable) [![CircleCI](https://circleci.com/gh/SortableJS/Sortable.svg?style=svg)](https://circleci.com/gh/SortableJS/Sortable) [![DeepScan grade](https://deepscan.io/api/teams/3901/projects/5666/branches/43977/badge/grade.svg)](https://deepscan.io/dashboard#view=project&tid=3901&pid=5666&bid=43977) [![](https://data.jsdelivr.com/v1/package/npm/sortablejs/badge)](https://www.jsdelivr.com/package/npm/sortablejs) [![npm](https://img.shields.io/npm/v/sortablejs.svg)](https://www.npmjs.com/package/sortablejs)

Sortable is a JavaScript library for reorderable drag-and-drop lists.

Demo: http://sortablejs.github.io/Sortable/

[<img width="250px" src="https://raw.githubusercontent.com/SortableJS/Sortable/HEAD/st/saucelabs.svg?sanitize=true">](https://saucelabs.com/)

## Features

 * Supports touch devices and [modern](http://caniuse.com/#search=drag) browsers (including IE9)
 * Can drag from one list to another or within the same list
 * CSS animation when moving items
 * Supports drag handles *and selectable text* (better than voidberg's html5sortable)
 * Smart auto-scrolling
 * Advanced swap detection
 * Smooth animations
 * [Multi-drag](https://github.com/SortableJS/Sortable/tree/master/plugins/MultiDrag) support
 * Support for CSS transforms
 * Built using native HTML5 drag and drop API
 * Supports
   * [Meteor](https://github.com/SortableJS/meteor-sortablejs)
   * Angular
     * [2.0+](https://github.com/SortableJS/angular-sortablejs)
     * [1.&ast;](https://github.com/SortableJS/angular-legacy-sortablejs)
   * React
     * [ES2015+](https://github.com/SortableJS/react-sortablejs)
     * [Mixin](https://github.com/SortableJS/react-mixin-sortablejs)
   * [Knockout](https://github.com/SortableJS/knockout-sortablejs)
   * [Polymer](https://github.com/SortableJS/polymer-sortablejs)
   * [Vue](https://github.com/SortableJS/Vue.Draggable)
   * [Ember](https://github.com/SortableJS/ember-sortablejs)
 * Supports any CSS library, e.g. [Bootstrap](#bs)
 * Simple API
 * Support for [plugins](#plugins)
 * [CDN](#cdn)
 * No jQuery required (but there is [support](https://github.com/SortableJS/jquery-sortablejs))
 * Typescript definitions at `@types/sortablejs`


<br/>


### Articles

 * [Dragging Multiple Items in Sortable](https://github.com/SortableJS/Sortable/wiki/Dragging-Multiple-Items-in-Sortable) (April 26, 2019)
 * [Swap Thresholds and Direction](https://github.com/SortableJS/Sortable/wiki/Swap-Thresholds-and-Direction) (December 2, 2018)
 * [Sortable v1.0 — New capabilities](https://github.com/SortableJS/Sortable/wiki/Sortable-v1.0-—-New-capabilities/) (December 22, 2014)
 * [Sorting with the help of HTML5 Drag'n'Drop API](https://github.com/SortableJS/Sortable/wiki/Sorting-with-the-help-of-HTML5-Drag'n'Drop-API/) (December 23, 2013)

<br/>

### Getting Started

Install with NPM:
```bash
npm install sortablejs --save
```

Install with Bower:
```bash
bower install --save sortablejs
```

Import into your project:
```js
// Default SortableJS
import Sortable from 'sortablejs';

// Core SortableJS (without default plugins)
import Sortable from 'sortablejs/modular/sortable.core.esm.js';

// Complete SortableJS (with all plugins)
import Sortable from 'sortablejs/modular/sortable.complete.esm.js';
```

Cherrypick plugins:
```js
// Cherrypick extra plugins
import Sortable, { MultiDrag, Swap } from 'sortablejs';

Sortable.mount(new MultiDrag(), new Swap());


// Cherrypick default plugins
import Sortable, { AutoScroll } from 'sortablejs/modular/sortable.core.esm.js';

Sortable.mount(new AutoScroll());
```


---


### Usage
```html
<ul id="items">
	<li>item 1</li>
	<li>item 2</li>
	<li>item 3</li>
</ul>
```

```js
var el = document.getElementById('items');
var sortable = Sortable.create(el);
```

You can use any element for the list and its elements, not just `ul`/`li`. Here is an [example with `div`s](https://jsbin.com/visimub/edit?html,js,output).


---


### Options
```js
var sortable = new Sortable(el, {
	group: "name",  // or { name: "...", pull: [true, false, 'clone', array], put: [true, false, array] }
	sort: true,  // sorting inside list
	delay: 0, // time in milliseconds to define when the sorting should start
	delayOnTouchOnly: false, // only delay if user is using touch
	touchStartThreshold: 0, // px, how many pixels the point should move before cancelling a delayed drag event
	disabled: false, // Disables the sortable if set to true.
	store: null,  // @see Store
	animation: 150,  // ms, animation speed moving items when sorting, `0` — without animation
	easing: "cubic-bezier(1, 0, 0, 1)", // Easing for animation. Defaults to null. See https://easings.net/ for examples.
	handle: ".my-handle",  // Drag handle selector within list items
	filter: ".ignore-elements",  // Selectors that do not lead to dragging (String or Function)
	preventOnFilter: true, // Call `event.preventDefault()` when triggered `filter`
	draggable: ".item",  // Specifies which items inside the element should be draggable

	dataIdAttr: 'data-id', // HTML attribute that is used by the `toArray()` method

	ghostClass: "sortable-ghost",  // Class name for the drop placeholder
	chosenClass: "sortable-chosen",  // Class name for the chosen item
	dragClass: "sortable-drag",  // Class name for the dragging item

	swapThreshold: 1, // Threshold of the swap zone
	invertSwap: false, // Will always use inverted swap zone if set to true
	invertedSwapThreshold: 1, // Threshold of the inverted swap zone (will be set to swapThreshold value by default)
	direction: 'horizontal', // Direction of Sortable (will be detected automatically if not given)

	forceFallback: false,  // ignore the HTML5 DnD behaviour and force the fallback to kick in

	fallbackClass: "sortable-fallback",  // Class name for the cloned DOM Element when using forceFallback
	fallbackOnBody: false,  // Appends the cloned DOM Element into the Document's Body
	fallbackTolerance: 0, // Specify in pixels how far the mouse should move before it's considered as a drag.

	dragoverBubble: false,
	removeCloneOnHide: true, // Remove the clone element when it is not showing, rather than just hiding it
	emptyInsertThreshold: 5, // px, distance mouse must be from empty sortable to insert drag element into it


	setData: function (/** DataTransfer */dataTransfer, /** HTMLElement*/dragEl) {
		dataTransfer.setData('Text', dragEl.textContent); // `dataTransfer` object of HTML5 DragEvent
	},

	// Element is chosen
	onChoose: function (/**Event*/evt) {
		evt.oldIndex;  // element index within parent
	},

	// Element is unchosen
	onUnchoose: function(/**Event*/evt) {
		// same properties as onEnd
	},

	// Element dragging started
	onStart: function (/**Event*/evt) {
		evt.oldIndex;  // element index within parent
	},

	// Element dragging ended
	onEnd: function (/**Event*/evt) {
		var itemEl = evt.item;  // dragged HTMLElement
		evt.to;    // target list
		evt.from;  // previous list
		evt.oldIndex;  // element's old index within old parent
		evt.newIndex;  // element's new index within new parent
		evt.oldDraggableIndex; // element's old index within old parent, only counting draggable elements
		evt.newDraggableIndex; // element's new index within new parent, only counting draggable elements
		evt.clone // the clone element
		evt.pullMode;  // when item is in another sortable: `"clone"` if cloning, `true` if moving
	},

	// Element is dropped into the list from another list
	onAdd: function (/**Event*/evt) {
		// same properties as onEnd
	},

	// Changed sorting within list
	onUpdate: function (/**Event*/evt) {
		// same properties as onEnd
	},

	// Called by any change to the list (add / update / remove)
	onSort: function (/**Event*/evt) {
		// same properties as onEnd
	},

	// Element is removed from the list into another list
	onRemove: function (/**Event*/evt) {
		// same properties as onEnd
	},

	// Attempt to drag a filtered element
	onFilter: function (/**Event*/evt) {
		var itemEl = evt.item;  // HTMLElement receiving the `mousedown|tapstart` event.
	},

	// Event when you move an item in the list or between lists
	onMove: function (/**Event*/evt, /**Event*/originalEvent) {
		// Example: https://jsbin.com/nawahef/edit?js,output
		evt.dragged; // dragged HTMLElement
		evt.draggedRect; // DOMRect {left, top, right, bottom}
		evt.related; // HTMLElement on which have guided
		evt.relatedRect; // DOMRect
		evt.willInsertAfter; // Boolean that is true if Sortable will insert drag element after target by default
		originalEvent.clientY; // mouse position
		// return false; — for cancel
		// return -1; — insert before target
		// return 1; — insert after target
		// return true; — keep default insertion point based on the direction
		// return void; — keep default insertion point based on the direction
	},

	// Called when creating a clone of element
	onClone: function (/**Event*/evt) {
		var origEl = evt.item;
		var cloneEl = evt.clone;
	},

	// Called when dragging element changes position
	onChange: function(/**Event*/evt) {
		evt.newIndex // most likely why this event is used is to get the dragging element's current index
		// same properties as onEnd
	}
});
```


---


#### `group` option
To drag elements from one list into another, both lists must have the same `group` value.
You can also define whether lists can give away, give and keep a copy (`clone`), and receive elements.

 * name: `String` — group name
 * pull: `true|false|["foo", "bar"]|'clone'|function` — ability to move from the list. `clone` — copy the item, rather than move. Or an array of group names which the elements may be put in. Defaults to `true`.
 * put: `true|false|["baz", "qux"]|function` — whether elements can be added from other lists, or an array of group names from which elements can be added.
 * revertClone: `boolean` — revert cloned element to initial position after moving to a another list.


Demo:
 - https://jsbin.com/hijetos/edit?js,output
 - https://jsbin.com/nacoyah/edit?js,output — use of complex logic in the `pull` and` put`
 - https://jsbin.com/bifuyab/edit?js,output — use `revertClone: true`


---


#### `sort` option
Allow sorting inside list.

Demo: https://jsbin.com/jayedig/edit?js,output


---


#### `delay` option
Time in milliseconds to define when the sorting should start.
Unfortunately, due to browser restrictions, delaying is not possible on IE or Edge with native drag & drop.

Demo: https://jsbin.com/zosiwah/edit?js,output


---


#### `delayOnTouchOnly` option
Whether or not the delay should be applied only if the user is using touch (eg. on a mobile device). No delay will be applied in any other case. Defaults to `false`.


---


#### `swapThreshold` option
Percentage of the target that the swap zone will take up, as a float between `0` and `1`.

[Read more](https://github.com/SortableJS/Sortable/wiki/Swap-Thresholds-and-Direction#swap-threshold)

Demo: http://sortablejs.github.io/Sortable#thresholds


---


#### `invertSwap` option
Set to `true` to set the swap zone to the sides of the target, for the effect of sorting "in between" items.

[Read more](https://github.com/SortableJS/Sortable/wiki/Swap-Thresholds-and-Direction#forcing-inverted-swap-zone)

Demo: http://sortablejs.github.io/Sortable#thresholds


---


#### `invertedSwapThreshold` option
Percentage of the target that the inverted swap zone will take up, as a float between `0` and `1`. If not given, will default to `swapThreshold`.

[Read more](https://github.com/SortableJS/Sortable/wiki/Swap-Thresholds-and-Direction#dealing-with-swap-glitching)


---


#### `direction` option
Direction that the Sortable should sort in. Can be set to `'vertical'`, `'horizontal'`, or a function, which will be called whenever a target is dragged over. Must return `'vertical'` or `'horizontal'`.

[Read more](https://github.com/SortableJS/Sortable/wiki/Swap-Thresholds-and-Direction#direction)


Example of direction detection for vertical list that includes full column and half column elements:

```js
Sortable.create(el, {
	direction: function(evt, target, dragEl) {
		if (target !== null && target.className.includes('half-column') && dragEl.className.includes('half-column')) {
			return 'horizontal';
		}
		return 'vertical';
	}
});
```


---


#### `touchStartThreshold` option
This option is similar to `fallbackTolerance` option.

When the `delay` option is set, some phones with very sensitive touch displays like the Samsung Galaxy S8 will fire
unwanted touchmove events even when your finger is not moving, resulting in the sort not triggering.

This option sets the minimum pointer movement that must occur before the delayed sorting is cancelled.

Values between 3 to 5 are good.


---


#### `disabled` options
Disables the sortable if set to `true`.

Demo: https://jsbin.com/sewokud/edit?js,output

```js
var sortable = Sortable.create(list);

document.getElementById("switcher").onclick = function () {
	var state = sortable.option("disabled"); // get

	sortable.option("disabled", !state); // set
};
```


---


#### `handle` option
To make list items draggable, Sortable disables text selection by the user.
That's not always desirable. To allow text selection, define a drag handler,
which is an area of every list element that allows it to be dragged around.

Demo: https://jsbin.com/numakuh/edit?html,js,output

```js
Sortable.create(el, {
	handle: ".my-handle"
});
```

```html
<ul>
	<li><span class="my-handle">::</span> list item text one
	<li><span class="my-handle">::</span> list item text two
</ul>
```

```css
.my-handle {
	cursor: move;
	cursor: -webkit-grabbing;
}
```


---


#### `filter` option


```js
Sortable.create(list, {
	filter: ".js-remove, .js-edit",
	onFilter: function (evt) {
		var item = evt.item,
			ctrl = evt.target;

		if (Sortable.utils.is(ctrl, ".js-remove")) {  // Click on remove button
			item.parentNode.removeChild(item); // remove sortable item
		}
		else if (Sortable.utils.is(ctrl, ".js-edit")) {  // Click on edit link
			// ...
		}
	}
})
```


---


#### `ghostClass` option
Class name for the drop placeholder (default `sortable-ghost`).

Demo: https://jsbin.com/henuyiw/edit?css,js,output

```css
.ghost {
  opacity: 0.4;
}
```

```js
Sortable.create(list, {
  ghostClass: "ghost"
});
```


---


#### `chosenClass` option
Class name for the chosen item  (default `sortable-chosen`).

Demo: https://jsbin.com/hoqufox/edit?css,js,output

```css
.chosen {
  color: #fff;
  background-color: #c00;
}
```

```js
Sortable.create(list, {
  delay: 500,
  chosenClass: "chosen"
});
```


---


#### `forceFallback` option
If set to `true`, the Fallback for non HTML5 Browser will be used, even if we are using an HTML5 Browser.
This gives us the possibility to test the behaviour for older Browsers even in newer Browser, or make the Drag 'n Drop feel more consistent between Desktop , Mobile and old Browsers.

On top of that, the Fallback always generates a copy of that DOM Element and appends the class `fallbackClass` defined in the options. This behaviour controls the look of this 'dragged' Element.

Demo: https://jsbin.com/sibiput/edit?html,css,js,output


---


#### `fallbackTolerance` option
Emulates the native drag threshold. Specify in pixels how far the mouse should move before it's considered as a drag.
Useful if the items are also clickable like in a list of links.

When the user clicks inside a sortable element, it's not uncommon for your hand to move a little between the time you press and the time you release.
Dragging only starts if you move the pointer past a certain tolerance, so that you don't accidentally start dragging every time you click.

3 to 5 are probably good values.


---


#### `dragoverBubble` option
If set to `true`, the dragover event will bubble to parent sortables. Works on both fallback and native dragover event.
By default, it is false, but Sortable will only stop bubbling the event once the element has been inserted into a parent Sortable, or *can* be inserted into a parent Sortable, but isn't at that specific time (due to animation, etc).

Since 1.8.0, you will probably want to leave this option as false. Before 1.8.0, it may need to be `true` for nested sortables to work.


---


#### `removeCloneOnHide` option
If set to `false`, the clone is hidden by having it's CSS `display` property set to `none`.
By default, this option is `true`, meaning Sortable will remove the cloned element from the DOM when it is supposed to be hidden.


---


#### `emptyInsertThreshold` option
The distance (in pixels) the mouse must be from an empty sortable while dragging for the drag element to be inserted into that sortable. Defaults to `5`. Set to `0` to disable this feature.

Demo: https://jsbin.com/becavoj/edit?js,output

An alternative to this option would be to set a padding on your list when it is empty.

For example:
```css
ul:empty {
  padding-bottom: 20px;
}
```

Warning: For `:empty` to work, it must have no node inside (even text one).

Demo:
https://jsbin.com/yunakeg/edit?html,css,js,output

---
### Event object ([demo](https://jsbin.com/fogujiv/edit?js,output))

 - to:`HTMLElement` — list, in which moved element
 - from:`HTMLElement` — previous list
 - item:`HTMLElement` — dragged element
 - clone:`HTMLElement`
 - oldIndex:`Number|undefined` — old index within parent
 - newIndex:`Number|undefined` — new index within parent
 - oldDraggableIndex: `Number|undefined` — old index within parent, only counting draggable elements
 - newDraggableIndex: `Number|undefined` — new index within parent, only counting draggable elements
 - pullMode:`String|Boolean|undefined` — Pull mode if dragging into another sortable (`"clone"`, `true`, or `false`), otherwise undefined


#### `move` event object
 - to:`HTMLElement`
 - from:`HTMLElement`
 - dragged:`HTMLElement`
 - draggedRect:`DOMRect`
 - related:`HTMLElement` — element on which have guided
 - relatedRect:`DOMRect`
 - willInsertAfter:`Boolean` — `true` if will element be inserted after target (or `false` if before)


---


### Methods


##### option(name:`String`[, value:`*`]):`*`
Get or set the option.



##### closest(el:`HTMLElement`[, selector:`String`]):`HTMLElement|null`
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.


##### toArray():`String[]`
Serializes the sortable's item `data-id`'s (`dataIdAttr` option) into an array of string.


##### sort(order:`String[]`, useAnimation:`Boolean`)
Sorts the elements according to the array.

```js
var order = sortable.toArray();
sortable.sort(order.reverse(), true); // apply
```


##### save()
Save the current sorting (see [store](#store))


##### destroy()
Removes the sortable functionality completely.


---


<a name="store"></a>
### Store
Saving and restoring of the sort.

```html
<ul>
	<li data-id="1">order</li>
	<li data-id="2">save</li>
	<li data-id="3">restore</li>
</ul>
```

```js
Sortable.create(el, {
	group: "localStorage-example",
	store: {
		/**
		 * Get the order of elements. Called once during initialization.
		 * @param   {Sortable}  sortable
		 * @returns {Array}
		 */
		get: function (sortable) {
			var order = localStorage.getItem(sortable.options.group.name);
			return order ? order.split('|') : [];
		},

		/**
		 * Save the order of elements. Called onEnd (when the item is dropped).
		 * @param {Sortable}  sortable
		 */
		set: function (sortable) {
			var order = sortable.toArray();
			localStorage.setItem(sortable.options.group.name, order.join('|'));
		}
	}
})
```


---


<a name="bs"></a>
### Bootstrap
Demo: https://jsbin.com/visimub/edit?html,js,output

```html
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css"/>


<!-- Latest Sortable -->
<script src="http://SortableJS.github.io/Sortable/Sortable.js"></script>


<!-- Simple List -->
<ul id="simpleList" class="list-group">
	<li class="list-group-item">This is <a href="http://SortableJS.github.io/Sortable/">Sortable</a></li>
	<li class="list-group-item">It works with Bootstrap...</li>
	<li class="list-group-item">...out of the box.</li>
	<li class="list-group-item">It has support for touch devices.</li>
	<li class="list-group-item">Just drag some elements around.</li>
</ul>

<script>
    // Simple list
    Sortable.create(simpleList, { /* options */ });
</script>
```


---


### Static methods & properties



##### Sortable.create(el:`HTMLElement`[, options:`Object`]):`Sortable`
Create new instance.


---


##### Sortable.active:`Sortable`
The active Sortable instance.


---


##### Sortable.dragged:`HTMLElement`
The element being dragged.


---


##### Sortable.ghost:`HTMLElement`
The ghost element.


---


##### Sortable.clone:`HTMLElement`
The clone element.


---


##### Sortable.get(element:`HTMLElement`):`Sortable`
Get the Sortable instance on an element.


---


##### Sortable.mount(plugin:`...SortablePlugin|SortablePlugin[]`)
Mounts a plugin to Sortable.


---


##### Sortable.utils
* on(el`:HTMLElement`, event`:String`, fn`:Function`) — attach an event handler function
* off(el`:HTMLElement`, event`:String`, fn`:Function`) — remove an event handler
* css(el`:HTMLElement`)`:Object` — get the values of all the CSS properties
* css(el`:HTMLElement`, prop`:String`)`:Mixed` — get the value of style properties
* css(el`:HTMLElement`, prop`:String`, value`:String`) — set one CSS properties
* css(el`:HTMLElement`, props`:Object`) — set more CSS properties
* find(ctx`:HTMLElement`, tagName`:String`[, iterator`:Function`])`:Array` — get elements by tag name
* bind(ctx`:Mixed`, fn`:Function`)`:Function` — Takes a function and returns a new one that will always have a particular context
* is(el`:HTMLElement`, selector`:String`)`:Boolean` — check the current matched set of elements against a selector
* closest(el`:HTMLElement`, selector`:String`[, ctx`:HTMLElement`])`:HTMLElement|Null` — 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
* clone(el`:HTMLElement`)`:HTMLElement` — create a deep copy of the set of matched elements
* toggleClass(el`:HTMLElement`, name`:String`, state`:Boolean`) — add or remove one classes from each element
* detectDirection(el`:HTMLElement`)`:String` — automatically detect the [direction](https://github.com/SortableJS/Sortable/wiki/Swap-Thresholds-and-Direction#direction) of the element as either `'vertical'` or `'horizontal'`
* index(el`:HTMLElement`, selector`:String`)`:Number` — index of the element within its parent for a selected set of elements
* getChild(el`:HTMLElement`, childNum`:Number`, options`:Object`, includeDragEl`:Boolean`):`HTMLElement` — get the draggable element at a given index of draggable elements within a Sortable instance
* expando`:String` — expando property name for internal use, sortableListElement[expando] returns the Sortable instance of that elemenet
---


### Plugins
#### Extra Plugins (included in complete versions)
 - [MultiDrag](https://github.com/SortableJS/Sortable/tree/master/plugins/MultiDrag)
 - [Swap](https://github.com/SortableJS/Sortable/tree/master/plugins/Swap)

#### Default Plugins (included in default versions)
 - [AutoScroll](https://github.com/SortableJS/Sortable/tree/master/plugins/AutoScroll)
 - [OnSpill](https://github.com/SortableJS/Sortable/tree/master/plugins/OnSpill)


---


<a name="cdn"></a>
### CDN

```html
<!-- jsDelivr :: Sortable :: Latest (https://www.jsdelivr.com/package/npm/sortablejs) -->
<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
```


---


### Contributing (Issue/PR)

Please, [read this](CONTRIBUTING.md).


---


## Contributors

### Code Contributors

This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
<a href="https://github.com/SortableJS/Sortable/graphs/contributors"><img src="https://opencollective.com/Sortable/contributors.svg?width=890&button=false" /></a>

### Financial Contributors

Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/Sortable/contribute)]

#### Individuals

<a href="https://opencollective.com/Sortable"><img src="https://opencollective.com/Sortable/individuals.svg?width=890"></a>

#### Organizations

Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/Sortable/contribute)]

<a href="https://opencollective.com/Sortable/organization/0/website"><img src="https://opencollective.com/Sortable/organization/0/avatar.svg"></a>
<a href="https://opencollective.com/Sortable/organization/1/website"><img src="https://opencollective.com/Sortable/organization/1/avatar.svg"></a>
<a href="https://opencollective.com/Sortable/organization/2/website"><img src="https://opencollective.com/Sortable/organization/2/avatar.svg"></a>
<a href="https://opencollective.com/Sortable/organization/3/website"><img src="https://opencollective.com/Sortable/organization/3/avatar.svg"></a>
<a href="https://opencollective.com/Sortable/organization/4/website"><img src="https://opencollective.com/Sortable/organization/4/avatar.svg"></a>
<a href="https://opencollective.com/Sortable/organization/5/website"><img src="https://opencollective.com/Sortable/organization/5/avatar.svg"></a>
<a href="https://opencollective.com/Sortable/organization/6/website"><img src="https://opencollective.com/Sortable/organization/6/avatar.svg"></a>
<a href="https://opencollective.com/Sortable/organization/7/website"><img src="https://opencollective.com/Sortable/organization/7/avatar.svg"></a>
<a href="https://opencollective.com/Sortable/organization/8/website"><img src="https://opencollective.com/Sortable/organization/8/avatar.svg"></a>
<a href="https://opencollective.com/Sortable/organization/9/website"><img src="https://opencollective.com/Sortable/organization/9/avatar.svg"></a>

## MIT LICENSE
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: Sortable.js
================================================
/**!
 * Sortable 1.15.7
 * @author	RubaXa   <trash@rubaxa.org>
 * @author	owenm    <owen23355@gmail.com>
 * @license MIT
 */
(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  typeof define === 'function' && define.amd ? define(factory) :
  (global = global || self, global.Sortable = factory());
}(this, (function () { 'use strict';

  function _arrayLikeToArray(r, a) {
    (null == a || a > r.length) && (a = r.length);
    for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
    return n;
  }
  function _arrayWithoutHoles(r) {
    if (Array.isArray(r)) return _arrayLikeToArray(r);
  }
  function _defineProperty(e, r, t) {
    return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
      value: t,
      enumerable: !0,
      configurable: !0,
      writable: !0
    }) : e[r] = t, e;
  }
  function _extends() {
    return _extends = Object.assign ? Object.assign.bind() : function (n) {
      for (var e = 1; e < arguments.length; e++) {
        var t = arguments[e];
        for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
      }
      return n;
    }, _extends.apply(null, arguments);
  }
  function _iterableToArray(r) {
    if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r);
  }
  function _nonIterableSpread() {
    throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
  }
  function ownKeys(e, r) {
    var t = Object.keys(e);
    if (Object.getOwnPropertySymbols) {
      var o = Object.getOwnPropertySymbols(e);
      r && (o = o.filter(function (r) {
        return Object.getOwnPropertyDescriptor(e, r).enumerable;
      })), t.push.apply(t, o);
    }
    return t;
  }
  function _objectSpread2(e) {
    for (var r = 1; r < arguments.length; r++) {
      var t = null != arguments[r] ? arguments[r] : {};
      r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {
        _defineProperty(e, r, t[r]);
      }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
        Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
      });
    }
    return e;
  }
  function _objectWithoutProperties(e, t) {
    if (null == e) return {};
    var o,
      r,
      i = _objectWithoutPropertiesLoose(e, t);
    if (Object.getOwnPropertySymbols) {
      var n = Object.getOwnPropertySymbols(e);
      for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]);
    }
    return i;
  }
  function _objectWithoutPropertiesLoose(r, e) {
    if (null == r) return {};
    var t = {};
    for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
      if (-1 !== e.indexOf(n)) continue;
      t[n] = r[n];
    }
    return t;
  }
  function _toConsumableArray(r) {
    return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();
  }
  function _toPrimitive(t, r) {
    if ("object" != typeof t || !t) return t;
    var e = t[Symbol.toPrimitive];
    if (void 0 !== e) {
      var i = e.call(t, r || "default");
      if ("object" != typeof i) return i;
      throw new TypeError("@@toPrimitive must return a primitive value.");
    }
    return ("string" === r ? String : Number)(t);
  }
  function _toPropertyKey(t) {
    var i = _toPrimitive(t, "string");
    return "symbol" == typeof i ? i : i + "";
  }
  function _typeof(o) {
    "@babel/helpers - typeof";

    return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
      return typeof o;
    } : function (o) {
      return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
    }, _typeof(o);
  }
  function _unsupportedIterableToArray(r, a) {
    if (r) {
      if ("string" == typeof r) return _arrayLikeToArray(r, a);
      var t = {}.toString.call(r).slice(8, -1);
      return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
    }
  }

  var version = "1.15.7";

  function userAgent(pattern) {
    if (typeof window !== 'undefined' && window.navigator) {
      return !! /*@__PURE__*/navigator.userAgent.match(pattern);
    }
  }
  var IE11OrLess = userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i);
  var Edge = userAgent(/Edge/i);
  var FireFox = userAgent(/firefox/i);
  var Safari = userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i);
  var IOS = userAgent(/iP(ad|od|hone)/i);
  var ChromeForAndroid = userAgent(/chrome/i) && userAgent(/android/i);

  var captureMode = {
    capture: false,
    passive: false
  };
  function on(el, event, fn) {
    el.addEventListener(event, fn, !IE11OrLess && captureMode);
  }
  function off(el, event, fn) {
    el.removeEventListener(event, fn, !IE11OrLess && captureMode);
  }
  function matches( /**HTMLElement*/el, /**String*/selector) {
    if (!selector) return;
    selector[0] === '>' && (selector = selector.substring(1));
    if (el) {
      try {
        if (el.matches) {
          return el.matches(selector);
        } else if (el.msMatchesSelector) {
          return el.msMatchesSelector(selector);
        } else if (el.webkitMatchesSelector) {
          return el.webkitMatchesSelector(selector);
        }
      } catch (_) {
        return false;
      }
    }
    return false;
  }
  function getParentOrHost(el) {
    return el.host && el !== document && el.host.nodeType && el.host !== el ? el.host : el.parentNode;
  }
  function closest( /**HTMLElement*/el, /**String*/selector, /**HTMLElement*/ctx, includeCTX) {
    if (el) {
      ctx = ctx || document;
      do {
        if (selector != null && (selector[0] === '>' ? el.parentNode === ctx && matches(el, selector) : matches(el, selector)) || includeCTX && el === ctx) {
          return el;
        }
        if (el === ctx) break;
        /* jshint boss:true */
      } while (el = getParentOrHost(el));
    }
    return null;
  }
  var R_SPACE = /\s+/g;
  function toggleClass(el, name, state) {
    if (el && name) {
      if (el.classList) {
        el.classList[state ? 'add' : 'remove'](name);
      } else {
        var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' ');
        el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' ');
      }
    }
  }
  function css(el, prop, val) {
    var style = el && el.style;
    if (style) {
      if (val === void 0) {
        if (document.defaultView && document.defaultView.getComputedStyle) {
          val = document.defaultView.getComputedStyle(el, '');
        } else if (el.currentStyle) {
          val = el.currentStyle;
        }
        return prop === void 0 ? val : val[prop];
      } else {
        if (!(prop in style) && prop.indexOf('webkit') === -1) {
          prop = '-webkit-' + prop;
        }
        style[prop] = val + (typeof val === 'string' ? '' : 'px');
      }
    }
  }
  function matrix(el, selfOnly) {
    var appliedTransforms = '';
    if (typeof el === 'string') {
      appliedTransforms = el;
    } else {
      do {
        var transform = css(el, 'transform');
        if (transform && transform !== 'none') {
          appliedTransforms = transform + ' ' + appliedTransforms;
        }
        /* jshint boss:true */
      } while (!selfOnly && (el = el.parentNode));
    }
    var matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix || window.MSCSSMatrix;
    /*jshint -W056 */
    return matrixFn && new matrixFn(appliedTransforms);
  }
  function find(ctx, tagName, iterator) {
    if (ctx) {
      var list = ctx.getElementsByTagName(tagName),
        i = 0,
        n = list.length;
      if (iterator) {
        for (; i < n; i++) {
          iterator(list[i], i);
        }
      }
      return list;
    }
    return [];
  }
  function getWindowScrollingElement() {
    var scrollingElement = document.scrollingElement;
    if (scrollingElement) {
      return scrollingElement;
    } else {
      return document.documentElement;
    }
  }

  /**
   * Returns the "bounding client rect" of given element
   * @param  {HTMLElement} el                       The element whose boundingClientRect is wanted
   * @param  {[Boolean]} relativeToContainingBlock  Whether the rect should be relative to the containing block of (including) the container
   * @param  {[Boolean]} relativeToNonStaticParent  Whether the rect should be relative to the relative parent of (including) the contaienr
   * @param  {[Boolean]} undoScale                  Whether the container's scale() should be undone
   * @param  {[HTMLElement]} container              The parent the element will be placed in
   * @return {Object}                               The boundingClientRect of el, with specified adjustments
   */
  function getRect(el, relativeToContainingBlock, relativeToNonStaticParent, undoScale, container) {
    if (!el.getBoundingClientRect && el !== window) return;
    var elRect, top, left, bottom, right, height, width;
    if (el !== window && el.parentNode && el !== getWindowScrollingElement()) {
      elRect = el.getBoundingClientRect();
      top = elRect.top;
      left = elRect.left;
      bottom = elRect.bottom;
      right = elRect.right;
      height = elRect.height;
      width = elRect.width;
    } else {
      top = 0;
      left = 0;
      bottom = window.innerHeight;
      right = window.innerWidth;
      height = window.innerHeight;
      width = window.innerWidth;
    }
    if ((relativeToContainingBlock || relativeToNonStaticParent) && el !== window) {
      // Adjust for translate()
      container = container || el.parentNode;

      // solves #1123 (see: https://stackoverflow.com/a/37953806/6088312)
      // Not needed on <= IE11
      if (!IE11OrLess) {
        do {
          if (container && container.getBoundingClientRect && (css(container, 'transform') !== 'none' || relativeToNonStaticParent && css(container, 'position') !== 'static')) {
            var containerRect = container.getBoundingClientRect();

            // Set relative to edges of padding box of container
            top -= containerRect.top + parseInt(css(container, 'border-top-width'));
            left -= containerRect.left + parseInt(css(container, 'border-left-width'));
            bottom = top + elRect.height;
            right = left + elRect.width;
            break;
          }
          /* jshint boss:true */
        } while (container = container.parentNode);
      }
    }
    if (undoScale && el !== window) {
      // Adjust for scale()
      var elMatrix = matrix(container || el),
        scaleX = elMatrix && elMatrix.a,
        scaleY = elMatrix && elMatrix.d;
      if (elMatrix) {
        top /= scaleY;
        left /= scaleX;
        width /= scaleX;
        height /= scaleY;
        bottom = top + height;
        right = left + width;
      }
    }
    return {
      top: top,
      left: left,
      bottom: bottom,
      right: right,
      width: width,
      height: height
    };
  }

  /**
   * Checks if a side of an element is scrolled past a side of its parents
   * @param  {HTMLElement}  el           The element who's side being scrolled out of view is in question
   * @param  {String}       elSide       Side of the element in question ('top', 'left', 'right', 'bottom')
   * @param  {String}       parentSide   Side of the parent in question ('top', 'left', 'right', 'bottom')
   * @return {HTMLElement}               The parent scroll element that the el's side is scrolled past, or null if there is no such element
   */
  function isScrolledPast(el, elSide, parentSide) {
    var parent = getParentAutoScrollElement(el, true),
      elSideVal = getRect(el)[elSide];

    /* jshint boss:true */
    while (parent) {
      var parentSideVal = getRect(parent)[parentSide],
        visible = void 0;
      if (parentSide === 'top' || parentSide === 'left') {
        visible = elSideVal >= parentSideVal;
      } else {
        visible = elSideVal <= parentSideVal;
      }
      if (!visible) return parent;
      if (parent === getWindowScrollingElement()) break;
      parent = getParentAutoScrollElement(parent, false);
    }
    return false;
  }

  /**
   * Gets nth child of el, ignoring hidden children, sortable's elements (does not ignore clone if it's visible)
   * and non-draggable elements
   * @param  {HTMLElement} el       The parent element
   * @param  {Number} childNum      The index of the child
   * @param  {Object} options       Parent Sortable's options
   * @return {HTMLElement}          The child at index childNum, or null if not found
   */
  function getChild(el, childNum, options, includeDragEl) {
    var currentChild = 0,
      i = 0,
      children = el.children;
    while (i < children.length) {
      if (children[i].style.display !== 'none' && children[i] !== Sortable.ghost && (includeDragEl || children[i] !== Sortable.dragged) && closest(children[i], options.draggable, el, false)) {
        if (currentChild === childNum) {
          return children[i];
        }
        currentChild++;
      }
      i++;
    }
    return null;
  }

  /**
   * Gets the last child in the el, ignoring ghostEl or invisible elements (clones)
   * @param  {HTMLElement} el       Parent element
   * @param  {selector} selector    Any other elements that should be ignored
   * @return {HTMLElement}          The last child, ignoring ghostEl
   */
  function lastChild(el, selector) {
    var last = el.lastElementChild;
    while (last && (last === Sortable.ghost || css(last, 'display') === 'none' || selector && !matches(last, selector))) {
      last = last.previousElementSibling;
    }
    return last || null;
  }

  /**
   * Returns the index of an element within its parent for a selected set of
   * elements
   * @param  {HTMLElement} el
   * @param  {selector} selector
   * @return {number}
   */
  function index(el, selector) {
    var index = 0;
    if (!el || !el.parentNode) {
      return -1;
    }

    /* jshint boss:true */
    while (el = el.previousElementSibling) {
      if (el.nodeName.toUpperCase() !== 'TEMPLATE' && el !== Sortable.clone && (!selector || matches(el, selector))) {
        index++;
      }
    }
    return index;
  }

  /**
   * Returns the scroll offset of the given element, added with all the scroll offsets of parent elements.
   * The value is returned in real pixels.
   * @param  {HTMLElement} el
   * @return {Array}             Offsets in the format of [left, top]
   */
  function getRelativeScrollOffset(el) {
    var offsetLeft = 0,
      offsetTop = 0,
      winScroller = getWindowScrollingElement();
    if (el) {
      do {
        var elMatrix = matrix(el),
          scaleX = elMatrix.a,
          scaleY = elMatrix.d;
        offsetLeft += el.scrollLeft * scaleX;
        offsetTop += el.scrollTop * scaleY;
      } while (el !== winScroller && (el = el.parentNode));
    }
    return [offsetLeft, offsetTop];
  }

  /**
   * Returns the index of the object within the given array
   * @param  {Array} arr   Array that may or may not hold the object
   * @param  {Object} obj  An object that has a key-value pair unique to and identical to a key-value pair in the object you want to find
   * @return {Number}      The index of the object in the array, or -1
   */
  function indexOfObject(arr, obj) {
    for (var i in arr) {
      if (!arr.hasOwnProperty(i)) continue;
      for (var key in obj) {
        if (obj.hasOwnProperty(key) && obj[key] === arr[i][key]) return Number(i);
      }
    }
    return -1;
  }
  function getParentAutoScrollElement(el, includeSelf) {
    // skip to window
    if (!el || !el.getBoundingClientRect) return getWindowScrollingElement();
    var elem = el;
    var gotSelf = false;
    do {
      // we don't need to get elem css if it isn't even overflowing in the first place (performance)
      if (elem.clientWidth < elem.scrollWidth || elem.clientHeight < elem.scrollHeight) {
        var elemCSS = css(elem);
        if (elem.clientWidth < elem.scrollWidth && (elemCSS.overflowX == 'auto' || elemCSS.overflowX == 'scroll') || elem.clientHeight < elem.scrollHeight && (elemCSS.overflowY == 'auto' || elemCSS.overflowY == 'scroll')) {
          if (!elem.getBoundingClientRect || elem === document.body) return getWindowScrollingElement();
          if (gotSelf || includeSelf) return elem;
          gotSelf = true;
        }
      }
      /* jshint boss:true */
    } while (elem = elem.parentNode);
    return getWindowScrollingElement();
  }
  function extend(dst, src) {
    if (dst && src) {
      for (var key in src) {
        if (src.hasOwnProperty(key)) {
          dst[key] = src[key];
        }
      }
    }
    return dst;
  }
  function isRectEqual(rect1, rect2) {
    return Math.round(rect1.top) === Math.round(rect2.top) && Math.round(rect1.left) === Math.round(rect2.left) && Math.round(rect1.height) === Math.round(rect2.height) && Math.round(rect1.width) === Math.round(rect2.width);
  }
  var _throttleTimeout;
  function throttle(callback, ms) {
    return function () {
      if (!_throttleTimeout) {
        var args = arguments,
          _this = this;
        if (args.length === 1) {
          callback.call(_this, args[0]);
        } else {
          callback.apply(_this, args);
        }
        _throttleTimeout = setTimeout(function () {
          _throttleTimeout = void 0;
        }, ms);
      }
    };
  }
  function cancelThrottle() {
    clearTimeout(_throttleTimeout);
    _throttleTimeout = void 0;
  }
  function scrollBy(el, x, y) {
    el.scrollLeft += x;
    el.scrollTop += y;
  }
  function clone(el) {
    var Polymer = window.Polymer;
    var $ = window.jQuery || window.Zepto;
    if (Polymer && Polymer.dom) {
      return Polymer.dom(el).cloneNode(true);
    } else if ($) {
      return $(el).clone(true)[0];
    } else {
      return el.cloneNode(true);
    }
  }
  function setRect(el, rect) {
    css(el, 'position', 'absolute');
    css(el, 'top', rect.top);
    css(el, 'left', rect.left);
    css(el, 'width', rect.width);
    css(el, 'height', rect.height);
  }
  function unsetRect(el) {
    css(el, 'position', '');
    css(el, 'top', '');
    css(el, 'left', '');
    css(el, 'width', '');
    css(el, 'height', '');
  }
  function getChildContainingRectFromElement(container, options, ghostEl) {
    var rect = {};
    Array.from(container.children).forEach(function (child) {
      var _rect$left, _rect$top, _rect$right, _rect$bottom;
      if (!closest(child, options.draggable, container, false) || child.animated || child === ghostEl) return;
      var childRect = getRect(child);
      rect.left = Math.min((_rect$left = rect.left) !== null && _rect$left !== void 0 ? _rect$left : Infinity, childRect.left);
      rect.top = Math.min((_rect$top = rect.top) !== null && _rect$top !== void 0 ? _rect$top : Infinity, childRect.top);
      rect.right = Math.max((_rect$right = rect.right) !== null && _rect$right !== void 0 ? _rect$right : -Infinity, childRect.right);
      rect.bottom = Math.max((_rect$bottom = rect.bottom) !== null && _rect$bottom !== void 0 ? _rect$bottom : -Infinity, childRect.bottom);
    });
    rect.width = rect.right - rect.left;
    rect.height = rect.bottom - rect.top;
    rect.x = rect.left;
    rect.y = rect.top;
    return rect;
  }
  var expando = 'Sortable' + new Date().getTime();

  function AnimationStateManager() {
    var animationStates = [],
      animationCallbackId;
    return {
      captureAnimationState: function captureAnimationState() {
        animationStates = [];
        if (!this.options.animation) return;
        var children = [].slice.call(this.el.children);
        children.forEach(function (child) {
          if (css(child, 'display') === 'none' || child === Sortable.ghost) return;
          animationStates.push({
            target: child,
            rect: getRect(child)
          });
          var fromRect = _objectSpread2({}, animationStates[animationStates.length - 1].rect);

          // If animating: compensate for current animation
          if (child.thisAnimationDuration) {
            var childMatrix = matrix(child, true);
            if (childMatrix) {
              fromRect.top -= childMatrix.f;
              fromRect.left -= childMatrix.e;
            }
          }
          child.fromRect = fromRect;
        });
      },
      addAnimationState: function addAnimationState(state) {
        animationStates.push(state);
      },
      removeAnimationState: function removeAnimationState(target) {
        animationStates.splice(indexOfObject(animationStates, {
          target: target
        }), 1);
      },
      animateAll: function animateAll(callback) {
        var _this = this;
        if (!this.options.animation) {
          clearTimeout(animationCallbackId);
          if (typeof callback === 'function') callback();
          return;
        }
        var animating = false,
          animationTime = 0;
        animationStates.forEach(function (state) {
          var time = 0,
            target = state.target,
            fromRect = target.fromRect,
            toRect = getRect(target),
            prevFromRect = target.prevFromRect,
            prevToRect = target.prevToRect,
            animatingRect = state.rect,
            targetMatrix = matrix(target, true);
          if (targetMatrix) {
            // Compensate for current animation
            toRect.top -= targetMatrix.f;
            toRect.left -= targetMatrix.e;
          }
          target.toRect = toRect;
          if (target.thisAnimationDuration) {
            // Could also check if animatingRect is between fromRect and toRect
            if (isRectEqual(prevFromRect, toRect) && !isRectEqual(fromRect, toRect) &&
            // Make sure animatingRect is on line between toRect & fromRect
            (animatingRect.top - toRect.top) / (animatingRect.left - toRect.left) === (fromRect.top - toRect.top) / (fromRect.left - toRect.left)) {
              // If returning to same place as started from animation and on same axis
              time = calculateRealTime(animatingRect, prevFromRect, prevToRect, _this.options);
            }
          }

          // if fromRect != toRect: animate
          if (!isRectEqual(toRect, fromRect)) {
            target.prevFromRect = fromRect;
            target.prevToRect = toRect;
            if (!time) {
              time = _this.options.animation;
            }
            _this.animate(target, animatingRect, toRect, time);
          }
          if (time) {
            animating = true;
            animationTime = Math.max(animationTime, time);
            clearTimeout(target.animationResetTimer);
            target.animationResetTimer = setTimeout(function () {
              target.animationTime = 0;
              target.prevFromRect = null;
              target.fromRect = null;
              target.prevToRect = null;
              target.thisAnimationDuration = null;
            }, time);
            target.thisAnimationDuration = time;
          }
        });
        clearTimeout(animationCallbackId);
        if (!animating) {
          if (typeof callback === 'function') callback();
        } else {
          animationCallbackId = setTimeout(function () {
            if (typeof callback === 'function') callback();
          }, animationTime);
        }
        animationStates = [];
      },
      animate: function animate(target, currentRect, toRect, duration) {
        if (duration) {
          css(target, 'transition', '');
          css(target, 'transform', '');
          var elMatrix = matrix(this.el),
            scaleX = elMatrix && elMatrix.a,
            scaleY = elMatrix && elMatrix.d,
            translateX = (currentRect.left - toRect.left) / (scaleX || 1),
            translateY = (currentRect.top - toRect.top) / (scaleY || 1);
          target.animatingX = !!translateX;
          target.animatingY = !!translateY;
          css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)');
          this.forRepaintDummy = repaint(target); // repaint

          css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : ''));
          css(target, 'transform', 'translate3d(0,0,0)');
          typeof target.animated === 'number' && clearTimeout(target.animated);
          target.animated = setTimeout(function () {
            css(target, 'transition', '');
            css(target, 'transform', '');
            target.animated = false;
            target.animatingX = false;
            target.animatingY = false;
          }, duration);
        }
      }
    };
  }
  function repaint(target) {
    return target.offsetWidth;
  }
  function calculateRealTime(animatingRect, fromRect, toRect, options) {
    return Math.sqrt(Math.pow(fromRect.top - animatingRect.top, 2) + Math.pow(fromRect.left - animatingRect.left, 2)) / Math.sqrt(Math.pow(fromRect.top - toRect.top, 2) + Math.pow(fromRect.left - toRect.left, 2)) * options.animation;
  }

  var plugins = [];
  var defaults = {
    initializeByDefault: true
  };
  var PluginManager = {
    mount: function mount(plugin) {
      // Set default static properties
      for (var option in defaults) {
        if (defaults.hasOwnProperty(option) && !(option in plugin)) {
          plugin[option] = defaults[option];
        }
      }
      plugins.forEach(function (p) {
        if (p.pluginName === plugin.pluginName) {
          throw "Sortable: Cannot mount plugin ".concat(plugin.pluginName, " more than once");
        }
      });
      plugins.push(plugin);
    },
    pluginEvent: function pluginEvent(eventName, sortable, evt) {
      var _this = this;
      this.eventCanceled = false;
      evt.cancel = function () {
        _this.eventCanceled = true;
      };
      var eventNameGlobal = eventName + 'Global';
      plugins.forEach(function (plugin) {
        if (!sortable[plugin.pluginName]) return;
        // Fire global events if it exists in this sortable
        if (sortable[plugin.pluginName][eventNameGlobal]) {
          sortable[plugin.pluginName][eventNameGlobal](_objectSpread2({
            sortable: sortable
          }, evt));
        }

        // Only fire plugin event if plugin is enabled in this sortable,
        // and plugin has event defined
        if (sortable.options[plugin.pluginName] && sortable[plugin.pluginName][eventName]) {
          sortable[plugin.pluginName][eventName](_objectSpread2({
            sortable: sortable
          }, evt));
        }
      });
    },
    initializePlugins: function initializePlugins(sortable, el, defaults, options) {
      plugins.forEach(function (plugin) {
        var pluginName = plugin.pluginName;
        if (!sortable.options[pluginName] && !plugin.initializeByDefault) return;
        var initialized = new plugin(sortable, el, sortable.options);
        initialized.sortable = sortable;
        initialized.options = sortable.options;
        sortable[pluginName] = initialized;

        // Add default options from plugin
        _extends(defaults, initialized.defaults);
      });
      for (var option in sortable.options) {
        if (!sortable.options.hasOwnProperty(option)) continue;
        var modified = this.modifyOption(sortable, option, sortable.options[option]);
        if (typeof modified !== 'undefined') {
          sortable.options[option] = modified;
        }
      }
    },
    getEventProperties: function getEventProperties(name, sortable) {
      var eventProperties = {};
      plugins.forEach(function (plugin) {
        if (typeof plugin.eventProperties !== 'function') return;
        _extends(eventProperties, plugin.eventProperties.call(sortable[plugin.pluginName], name));
      });
      return eventProperties;
    },
    modifyOption: function modifyOption(sortable, name, value) {
      var modifiedValue;
      plugins.forEach(function (plugin) {
        // Plugin must exist on the Sortable
        if (!sortable[plugin.pluginName]) return;

        // If static option listener exists for this option, call in the context of the Sortable's instance of this plugin
        if (plugin.optionListeners && typeof plugin.optionListeners[name] === 'function') {
          modifiedValue = plugin.optionListeners[name].call(sortable[plugin.pluginName], value);
        }
      });
      return modifiedValue;
    }
  };

  function dispatchEvent(_ref) {
    var sortable = _ref.sortable,
      rootEl = _ref.rootEl,
      name = _ref.name,
      targetEl = _ref.targetEl,
      cloneEl = _ref.cloneEl,
      toEl = _ref.toEl,
      fromEl = _ref.fromEl,
      oldIndex = _ref.oldIndex,
      newIndex = _ref.newIndex,
      oldDraggableIndex = _ref.oldDraggableIndex,
      newDraggableIndex = _ref.newDraggableIndex,
      originalEvent = _ref.originalEvent,
      putSortable = _ref.putSortable,
      extraEventProperties = _ref.extraEventProperties;
    sortable = sortable || rootEl && rootEl[expando];
    if (!sortable) return;
    var evt,
      options = sortable.options,
      onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1);
    // Support for new CustomEvent feature
    if (window.CustomEvent && !IE11OrLess && !Edge) {
      evt = new CustomEvent(name, {
        bubbles: true,
        cancelable: true
      });
    } else {
      evt = document.createEvent('Event');
      evt.initEvent(name, true, true);
    }
    evt.to = toEl || rootEl;
    evt.from = fromEl || rootEl;
    evt.item = targetEl || rootEl;
    evt.clone = cloneEl;
    evt.oldIndex = oldIndex;
    evt.newIndex = newIndex;
    evt.oldDraggableIndex = oldDraggableIndex;
    evt.newDraggableIndex = newDraggableIndex;
    evt.originalEvent = originalEvent;
    evt.pullMode = putSortable ? putSortable.lastPutMode : undefined;
    var allEventProperties = _objectSpread2(_objectSpread2({}, extraEventProperties), PluginManager.getEventProperties(name, sortable));
    for (var option in allEventProperties) {
      evt[option] = allEventProperties[option];
    }
    if (rootEl) {
      rootEl.dispatchEvent(evt);
    }
    if (options[onName]) {
      options[onName].call(sortable, evt);
    }
  }

  var _excluded = ["evt"];
  var pluginEvent = function pluginEvent(eventName, sortable) {
    var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
      originalEvent = _ref.evt,
      data = _objectWithoutProperties(_ref, _excluded);
    PluginManager.pluginEvent.bind(Sortable)(eventName, sortable, _objectSpread2({
      dragEl: dragEl,
      parentEl: parentEl,
      ghostEl: ghostEl,
      rootEl: rootEl,
      nextEl: nextEl,
      lastDownEl: lastDownEl,
      cloneEl: cloneEl,
      cloneHidden: cloneHidden,
      dragStarted: moved,
      putSortable: putSortable,
      activeSortable: Sortable.active,
      originalEvent: originalEvent,
      oldIndex: oldIndex,
      oldDraggableIndex: oldDraggableIndex,
      newIndex: newIndex,
      newDraggableIndex: newDraggableIndex,
      hideGhostForTarget: _hideGhostForTarget,
      unhideGhostForTarget: _unhideGhostForTarget,
      cloneNowHidden: function cloneNowHidden() {
        cloneHidden = true;
      },
      cloneNowShown: function cloneNowShown() {
        cloneHidden = false;
      },
      dispatchSortableEvent: function dispatchSortableEvent(name) {
        _dispatchEvent({
          sortable: sortable,
          name: name,
          originalEvent: originalEvent
        });
      }
    }, data));
  };
  function _dispatchEvent(info) {
    dispatchEvent(_objectSpread2({
      putSortable: putSortable,
      cloneEl: cloneEl,
      targetEl: dragEl,
      rootEl: rootEl,
      oldIndex: oldIndex,
      oldDraggableIndex: oldDraggableIndex,
      newIndex: newIndex,
      newDraggableIndex: newDraggableIndex
    }, info));
  }
  var dragEl,
    parentEl,
    ghostEl,
    rootEl,
    nextEl,
    lastDownEl,
    cloneEl,
    cloneHidden,
    oldIndex,
    newIndex,
    oldDraggableIndex,
    newDraggableIndex,
    activeGroup,
    putSortable,
    awaitingDragStarted = false,
    ignoreNextClick = false,
    sortables = [],
    tapEvt,
    touchEvt,
    lastDx,
    lastDy,
    tapDistanceLeft,
    tapDistanceTop,
    moved,
    lastTarget,
    lastDirection,
    pastFirstInvertThresh = false,
    isCircumstantialInvert = false,
    targetMoveDistance,
    // For positioning ghost absolutely
    ghostRelativeParent,
    ghostRelativeParentInitialScroll = [],
    // (left, top)

    _silent = false,
    savedInputChecked = [];

  /** @const */
  var documentExists = typeof document !== 'undefined',
    PositionGhostAbsolutely = IOS,
    CSSFloatProperty = Edge || IE11OrLess ? 'cssFloat' : 'float',
    // This will not pass for IE9, because IE9 DnD only works on anchors
    supportDraggable = documentExists && !ChromeForAndroid && !IOS && 'draggable' in document.createElement('div'),
    supportCssPointerEvents = function () {
      if (!documentExists) return;
      // false when <= IE11
      if (IE11OrLess) {
        return false;
      }
      var el = document.createElement('x');
      el.style.cssText = 'pointer-events:auto';
      return el.style.pointerEvents === 'auto';
    }(),
    _detectDirection = function _detectDirection(el, options) {
      var elCSS = css(el),
        elWidth = parseInt(elCSS.width) - parseInt(elCSS.paddingLeft) - parseInt(elCSS.paddingRight) - parseInt(elCSS.borderLeftWidth) - parseInt(elCSS.borderRightWidth),
        child1 = getChild(el, 0, options),
        child2 = getChild(el, 1, options),
        firstChildCSS = child1 && css(child1),
        secondChildCSS = child2 && css(child2),
        firstChildWidth = firstChildCSS && parseInt(firstChildCSS.marginLeft) + parseInt(firstChildCSS.marginRight) + getRect(child1).width,
        secondChildWidth = secondChildCSS && parseInt(secondChildCSS.marginLeft) + parseInt(secondChildCSS.marginRight) + getRect(child2).width;
      if (elCSS.display === 'flex') {
        return elCSS.flexDirection === 'column' || elCSS.flexDirection === 'column-reverse' ? 'vertical' : 'horizontal';
      }
      if (elCSS.display === 'grid') {
        return elCSS.gridTemplateColumns.split(' ').length <= 1 ? 'vertical' : 'horizontal';
      }
      if (child1 && firstChildCSS["float"] && firstChildCSS["float"] !== 'none') {
        var touchingSideChild2 = firstChildCSS["float"] === 'left' ? 'left' : 'right';
        return child2 && (secondChildCSS.clear === 'both' || secondChildCSS.clear === touchingSideChild2) ? 'vertical' : 'horizontal';
      }
      return child1 && (firstChildCSS.display === 'block' || firstChildCSS.display === 'flex' || firstChildCSS.display === 'table' || firstChildCSS.display === 'grid' || firstChildWidth >= elWidth && elCSS[CSSFloatProperty] === 'none' || child2 && elCSS[CSSFloatProperty] === 'none' && firstChildWidth + secondChildWidth > elWidth) ? 'vertical' : 'horizontal';
    },
    _dragElInRowColumn = function _dragElInRowColumn(dragRect, targetRect, vertical) {
      var dragElS1Opp = vertical ? dragRect.left : dragRect.top,
        dragElS2Opp = vertical ? dragRect.right : dragRect.bottom,
        dragElOppLength = vertical ? dragRect.width : dragRect.height,
        targetS1Opp = vertical ? targetRect.left : targetRect.top,
        targetS2Opp = vertical ? targetRect.right : targetRect.bottom,
        targetOppLength = vertical ? targetRect.width : targetRect.height;
      return dragElS1Opp === targetS1Opp || dragElS2Opp === targetS2Opp || dragElS1Opp + dragElOppLength / 2 === targetS1Opp + targetOppLength / 2;
    },
    /**
     * Detects first nearest empty sortable to X and Y position using emptyInsertThreshold.
     * @param  {Number} x      X position
     * @param  {Number} y      Y position
     * @return {HTMLElement}   Element of the first found nearest Sortable
     */
    _detectNearestEmptySortable = function _detectNearestEmptySortable(x, y) {
      var ret;
      sortables.some(function (sortable) {
        var threshold = sortable[expando].options.emptyInsertThreshold;
        if (!threshold || lastChild(sortable)) return;
        var rect = getRect(sortable),
          insideHorizontally = x >= rect.left - threshold && x <= rect.right + threshold,
          insideVertically = y >= rect.top - threshold && y <= rect.bottom + threshold;
        if (insideHorizontally && insideVertically) {
          return ret = sortable;
        }
      });
      return ret;
    },
    _prepareGroup = function _prepareGroup(options) {
      function toFn(value, pull) {
        return function (to, from, dragEl, evt) {
          var sameGroup = to.options.group.name && from.options.group.name && to.options.group.name === from.options.group.name;
          if (value == null && (pull || sameGroup)) {
            // Default pull value
            // Default pull and put value if same group
            return true;
          } else if (value == null || value === false) {
            return false;
          } else if (pull && value === 'clone') {
            return value;
          } else if (typeof value === 'function') {
            return toFn(value(to, from, dragEl, evt), pull)(to, from, dragEl, evt);
          } else {
            var otherGroup = (pull ? to : from).options.group.name;
            return value === true || typeof value === 'string' && value === otherGroup || value.join && value.indexOf(otherGroup) > -1;
          }
        };
      }
      var group = {};
      var originalGroup = options.group;
      if (!originalGroup || _typeof(originalGroup) != 'object') {
        originalGroup = {
          name: originalGroup
        };
      }
      group.name = originalGroup.name;
      group.checkPull = toFn(originalGroup.pull, true);
      group.checkPut = toFn(originalGroup.put);
      group.revertClone = originalGroup.revertClone;
      options.group = group;
    },
    _hideGhostForTarget = function _hideGhostForTarget() {
      if (!supportCssPointerEvents && ghostEl) {
        css(ghostEl, 'display', 'none');
      }
    },
    _unhideGhostForTarget = function _unhideGhostForTarget() {
      if (!supportCssPointerEvents && ghostEl) {
        css(ghostEl, 'display', '');
      }
    };

  // #1184 fix - Prevent click event on fallback if dragged but item not changed position
  if (documentExists && !ChromeForAndroid) {
    document.addEventListener('click', function (evt) {
      if (ignoreNextClick) {
        evt.preventDefault();
        evt.stopPropagation && evt.stopPropagation();
        evt.stopImmediatePropagation && evt.stopImmediatePropagation();
        ignoreNextClick = false;
        return false;
      }
    }, true);
  }
  var nearestEmptyInsertDetectEvent = function nearestEmptyInsertDetectEvent(evt) {
    if (dragEl) {
      evt = evt.touches ? evt.touches[0] : evt;
      var nearest = _detectNearestEmptySortable(evt.clientX, evt.clientY);
      if (nearest) {
        // Create imitation event
        var event = {};
        for (var i in evt) {
          if (evt.hasOwnProperty(i)) {
            event[i] = evt[i];
          }
        }
        event.target = event.rootEl = nearest;
        event.preventDefault = void 0;
        event.stopPropagation = void 0;
        nearest[expando]._onDragOver(event);
      }
    }
  };
  var _checkOutsideTargetEl = function _checkOutsideTargetEl(evt) {
    if (dragEl) {
      dragEl.parentNode[expando]._isOutsideThisEl(evt.target);
    }
  };

  /**
   * @class  Sortable
   * @param  {HTMLElement}  el
   * @param  {Object}       [options]
   */
  function Sortable(el, options) {
    if (!(el && el.nodeType && el.nodeType === 1)) {
      throw "Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(el));
    }
    this.el = el; // root element
    this.options = options = _extends({}, options);

    // Export instance
    el[expando] = this;
    var defaults = {
      group: null,
      sort: true,
      disabled: false,
      store: null,
      handle: null,
      draggable: /^[uo]l$/i.test(el.nodeName) ? '>li' : '>*',
      swapThreshold: 1,
      // percentage; 0 <= x <= 1
      invertSwap: false,
      // invert always
      invertedSwapThreshold: null,
      // will be set to same as swapThreshold if default
      removeCloneOnHide: true,
      direction: function direction() {
        return _detectDirection(el, this.options);
      },
      ghostClass: 'sortable-ghost',
      chosenClass: 'sortable-chosen',
      dragClass: 'sortable-drag',
      ignore: 'a, img',
      filter: null,
      preventOnFilter: true,
      animation: 0,
      easing: null,
      setData: function setData(dataTransfer, dragEl) {
        dataTransfer.setData('Text', dragEl.textContent);
      },
      dropBubble: false,
      dragoverBubble: false,
      dataIdAttr: 'data-id',
      delay: 0,
      delayOnTouchOnly: false,
      touchStartThreshold: (Number.parseInt ? Number : window).parseInt(window.devicePixelRatio, 10) || 1,
      forceFallback: false,
      fallbackClass: 'sortable-fallback',
      fallbackOnBody: false,
      fallbackTolerance: 0,
      fallbackOffset: {
        x: 0,
        y: 0
      },
      // Disabled on Safari: #1571; Enabled on Safari IOS: #2244
      supportPointer: Sortable.supportPointer !== false && 'PointerEvent' in window && (!Safari || IOS),
      emptyInsertThreshold: 5
    };
    PluginManager.initializePlugins(this, el, defaults);

    // Set default options
    for (var name in defaults) {
      !(name in options) && (options[name] = defaults[name]);
    }
    _prepareGroup(options);

    // Bind all private methods
    for (var fn in this) {
      if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
        this[fn] = this[fn].bind(this);
      }
    }

    // Setup drag mode
    this.nativeDraggable = options.forceFallback ? false : supportDraggable;
    if (this.nativeDraggable) {
      // Touch start threshold cannot be greater than the native dragstart threshold
      this.options.touchStartThreshold = 1;
    }

    // Bind events
    if (options.supportPointer) {
      on(el, 'pointerdown', this._onTapStart);
    } else {
      on(el, 'mousedown', this._onTapStart);
      on(el, 'touchstart', this._onTapStart);
    }
    if (this.nativeDraggable) {
      on(el, 'dragover', this);
      on(el, 'dragenter', this);
    }
    sortables.push(this.el);

    // Restore sorting
    options.store && options.store.get && this.sort(options.store.get(this) || []);

    // Add animation state manager
    _extends(this, AnimationStateManager());
  }
  Sortable.prototype = /** @lends Sortable.prototype */{
    constructor: Sortable,
    _isOutsideThisEl: function _isOutsideThisEl(target) {
      if (!this.el.contains(target) && target !== this.el) {
        lastTarget = null;
      }
    },
    _getDirection: function _getDirection(evt, target) {
      return typeof this.options.direction === 'function' ? this.options.direction.call(this, evt, target, dragEl) : this.options.direction;
    },
    _onTapStart: function _onTapStart( /** Event|TouchEvent */evt) {
      if (!evt.cancelable) return;
      var _this = this,
        el = this.el,
        options = this.options,
        preventOnFilter = options.preventOnFilter,
        type = evt.type,
        touch = evt.touches && evt.touches[0] || evt.pointerType && evt.pointerType === 'touch' && evt,
        target = (touch || evt).target,
        originalTarget = evt.target.shadowRoot && (evt.path && evt.path[0] || evt.composedPath && evt.composedPath()[0]) || target,
        filter = options.filter;
      _saveInputCheckedState(el);

      // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group.
      if (dragEl) {
        return;
      }
      if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) {
        return; // only left button and enabled
      }

      // cancel dnd if original target is content editable
      if (originalTarget.isContentEditable) {
        return;
      }

      // Safari ignores further event handling after mousedown
      if (!this.nativeDraggable && Safari && target && target.tagName.toUpperCase() === 'SELECT') {
        return;
      }
      target = closest(target, options.draggable, el, false);
      if (target && target.animated) {
        return;
      }
      if (lastDownEl === target) {
        // Ignoring duplicate `down`
        return;
      }

      // Get the index of the dragged element within its parent
      oldIndex = index(target);
      oldDraggableIndex = index(target, options.draggable);

      // Check filter
      if (typeof filter === 'function') {
        if (filter.call(this, evt, target, this)) {
          _dispatchEvent({
            sortable: _this,
            rootEl: originalTarget,
            name: 'filter',
            targetEl: target,
            toEl: el,
            fromEl: el
          });
          pluginEvent('filter', _this, {
            evt: evt
          });
          preventOnFilter && evt.preventDefault();
          return; // cancel dnd
        }
      } else if (filter) {
        filter = filter.split(',').some(function (criteria) {
          criteria = closest(originalTarget, criteria.trim(), el, false);
          if (criteria) {
            _dispatchEvent({
              sortable: _this,
              rootEl: criteria,
              name: 'filter',
              targetEl: target,
              fromEl: el,
              toEl: el
            });
            pluginEvent('filter', _this, {
              evt: evt
            });
            return true;
          }
        });
        if (filter) {
          preventOnFilter && evt.preventDefault();
          return; // cancel dnd
        }
      }
      if (options.handle && !closest(originalTarget, options.handle, el, false)) {
        return;
      }

      // Prepare `dragstart`
      this._prepareDragStart(evt, touch, target);
    },
    _prepareDragStart: function _prepareDragStart( /** Event */evt, /** Touch */touch, /** HTMLElement */target) {
      var _this = this,
        el = _this.el,
        options = _this.options,
        ownerDocument = el.ownerDocument,
        dragStartFn;
      if (target && !dragEl && target.parentNode === el) {
        var dragRect = getRect(target);
        rootEl = el;
        dragEl = target;
        parentEl = dragEl.parentNode;
        nextEl = dragEl.nextSibling;
        lastDownEl = target;
        activeGroup = options.group;
        Sortable.dragged = dragEl;
        tapEvt = {
          target: dragEl,
          clientX: (touch || evt).clientX,
          clientY: (touch || evt).clientY
        };
        tapDistanceLeft = tapEvt.clientX - dragRect.left;
        tapDistanceTop = tapEvt.clientY - dragRect.top;
        this._lastX = (touch || evt).clientX;
        this._lastY = (touch || evt).clientY;
        dragEl.style['will-change'] = 'all';
        dragStartFn = function dragStartFn() {
          pluginEvent('delayEnded', _this, {
            evt: evt
          });
          if (Sortable.eventCanceled) {
            _this._onDrop();
            return;
          }
          // Delayed drag has been triggered
          // we can re-enable the events: touchmove/mousemove
          _this._disableDelayedDragEvents();
          if (!FireFox && _this.nativeDraggable) {
            dragEl.draggable = true;
          }

          // Bind the events: dragstart/dragend
          _this._triggerDragStart(evt, touch);

          // Drag start event
          _dispatchEvent({
            sortable: _this,
            name: 'choose',
            originalEvent: evt
          });

          // Chosen item
          toggleClass(dragEl, options.chosenClass, true);
        };

        // Disable "draggable"
        options.ignore.split(',').forEach(function (criteria) {
          find(dragEl, criteria.trim(), _disableDraggable);
        });
        on(ownerDocument, 'dragover', nearestEmptyInsertDetectEvent);
        on(ownerDocument, 'mousemove', nearestEmptyInsertDetectEvent);
        on(ownerDocument, 'touchmove', nearestEmptyInsertDetectEvent);
        if (options.supportPointer) {
          on(ownerDocument, 'pointerup', _this._onDrop);
          // Native D&D triggers pointercancel
          !this.nativeDraggable && on(ownerDocument, 'pointercancel', _this._onDrop);
        } else {
          on(ownerDocument, 'mouseup', _this._onDrop);
          on(ownerDocument, 'touchend', _this._onDrop);
          on(ownerDocument, 'touchcancel', _this._onDrop);
        }

        // Make dragEl draggable (must be before delay for FireFox)
        if (FireFox && this.nativeDraggable) {
          this.options.touchStartThreshold = 4;
          dragEl.draggable = true;
        }
        pluginEvent('delayStart', this, {
          evt: evt
        });

        // Delay is impossible for native DnD in Edge or IE
        if (options.delay && (!options.delayOnTouchOnly || touch) && (!this.nativeDraggable || !(Edge || IE11OrLess))) {
          if (Sortable.eventCanceled) {
            this._onDrop();
            return;
          }
          // If the user moves the pointer or let go the click or touch
          // before the delay has been reached:
          // disable the delayed drag
          if (options.supportPointer) {
            on(ownerDocument, 'pointerup', _this._disableDelayedDrag);
            on(ownerDocument, 'pointercancel', _this._disableDelayedDrag);
          } else {
            on(ownerDocument, 'mouseup', _this._disableDelayedDrag);
            on(ownerDocument, 'touchend', _this._disableDelayedDrag);
            on(ownerDocument, 'touchcancel', _this._disableDelayedDrag);
          }
          on(ownerDocument, 'mousemove', _this._delayedDragTouchMoveHandler);
          on(ownerDocument, 'touchmove', _this._delayedDragTouchMoveHandler);
          options.supportPointer && on(ownerDocument, 'pointermove', _this._delayedDragTouchMoveHandler);
          _this._dragStartTimer = setTimeout(dragStartFn, options.delay);
        } else {
          dragStartFn();
        }
      }
    },
    _delayedDragTouchMoveHandler: function _delayedDragTouchMoveHandler( /** TouchEvent|PointerEvent **/e) {
      var touch = e.touches ? e.touches[0] : e;
      if (Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) >= Math.floor(this.options.touchStartThreshold / (this.nativeDraggable && window.devicePixelRatio || 1))) {
        this._disableDelayedDrag();
      }
    },
    _disableDelayedDrag: function _disableDelayedDrag() {
      dragEl && _disableDraggable(dragEl);
      clearTimeout(this._dragStartTimer);
      this._disableDelayedDragEvents();
    },
    _disableDelayedDragEvents: function _disableDelayedDragEvents() {
      var ownerDocument = this.el.ownerDocument;
      off(ownerDocument, 'mouseup', this._disableDelayedDrag);
      off(ownerDocument, 'touchend', this._disableDelayedDrag);
      off(ownerDocument, 'touchcancel', this._disableDelayedDrag);
      off(ownerDocument, 'pointerup', this._disableDelayedDrag);
      off(ownerDocument, 'pointercancel', this._disableDelayedDrag);
      off(ownerDocument, 'mousemove', this._delayedDragTouchMoveHandler);
      off(ownerDocument, 'touchmove', this._delayedDragTouchMoveHandler);
      off(ownerDocument, 'pointermove', this._delayedDragTouchMoveHandler);
    },
    _triggerDragStart: function _triggerDragStart( /** Event */evt, /** Touch */touch) {
      touch = touch || evt.pointerType == 'touch' && evt;
      if (!this.nativeDraggable || touch) {
        if (this.options.supportPointer) {
          on(document, 'pointermove', this._onTouchMove);
        } else if (touch) {
          on(document, 'touchmove', this._onTouchMove);
        } else {
          on(document, 'mousemove', this._onTouchMove);
        }
      } else {
        on(dragEl, 'dragend', this);
        on(rootEl, 'dragstart', this._onDragStart);
      }
      try {
        if (document.selection) {
          _nextTick(function () {
            document.selection.empty();
          });
        } else {
          window.getSelection().removeAllRanges();
        }
      } catch (err) {}
    },
    _dragStarted: function _dragStarted(fallback, evt) {
      awaitingDragStarted = false;
      if (rootEl && dragEl) {
        pluginEvent('dragStarted', this, {
          evt: evt
        });
        if (this.nativeDraggable) {
          on(document, 'dragover', _checkOutsideTargetEl);
        }
        var options = this.options;

        // Apply effect
        !fallback && toggleClass(dragEl, options.dragClass, false);
        toggleClass(dragEl, options.ghostClass, true);
        Sortable.active = this;
        fallback && this._appendGhost();

        // Drag start event
        _dispatchEvent({
          sortable: this,
          name: 'start',
          originalEvent: evt
        });
      } else {
        this._nulling();
      }
    },
    _emulateDragOver: function _emulateDragOver() {
      if (touchEvt) {
        this._lastX = touchEvt.clientX;
        this._lastY = touchEvt.clientY;
        _hideGhostForTarget();
        var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
        var parent = target;
        while (target && target.shadowRoot) {
          target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
          if (target === parent) break;
          parent = target;
        }
        dragEl.parentNode[expando]._isOutsideThisEl(target);
        if (parent) {
          do {
            if (parent[expando]) {
              var inserted = void 0;
              inserted = parent[expando]._onDragOver({
                clientX: touchEvt.clientX,
                clientY: touchEvt.clientY,
                target: target,
                rootEl: parent
              });
              if (inserted && !this.options.dragoverBubble) {
                break;
              }
            }
            target = parent; // store last element
          }
          /* jshint boss:true */ while (parent = getParentOrHost(parent));
        }
        _unhideGhostForTarget();
      }
    },
    _onTouchMove: function _onTouchMove( /**TouchEvent*/evt) {
      if (tapEvt) {
        var options = this.options,
          fallbackTolerance = options.fallbackTolerance,
          fallbackOffset = options.fallbackOffset,
          touch = evt.touches ? evt.touches[0] : evt,
          ghostMatrix = ghostEl && matrix(ghostEl, true),
          scaleX = ghostEl && ghostMatrix && ghostMatrix.a,
          scaleY = ghostEl && ghostMatrix && ghostMatrix.d,
          relativeScrollOffset = PositionGhostAbsolutely && ghostRelativeParent && getRelativeScrollOffset(ghostRelativeParent),
          dx = (touch.clientX - tapEvt.clientX + fallbackOffset.x) / (scaleX || 1) + (relativeScrollOffset ? relativeScrollOffset[0] - ghostRelativeParentInitialScroll[0] : 0) / (scaleX || 1),
          dy = (touch.clientY - tapEvt.clientY + fallbackOffset.y) / (scaleY || 1) + (relativeScrollOffset ? relativeScrollOffset[1] - ghostRelativeParentInitialScroll[1] : 0) / (scaleY || 1);

        // only set the status to dragging, when we are actually dragging
        if (!Sortable.active && !awaitingDragStarted) {
          if (fallbackTolerance && Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) < fallbackTolerance) {
            return;
          }
          this._onDragStart(evt, true);
        }
        if (ghostEl) {
          if (ghostMatrix) {
            ghostMatrix.e += dx - (lastDx || 0);
            ghostMatrix.f += dy - (lastDy || 0);
          } else {
            ghostMatrix = {
              a: 1,
              b: 0,
              c: 0,
              d: 1,
              e: dx,
              f: dy
            };
          }
          var cssMatrix = "matrix(".concat(ghostMatrix.a, ",").concat(ghostMatrix.b, ",").concat(ghostMatrix.c, ",").concat(ghostMatrix.d, ",").concat(ghostMatrix.e, ",").concat(ghostMatrix.f, ")");
          css(ghostEl, 'webkitTransform', cssMatrix);
          css(ghostEl, 'mozTransform', cssMatrix);
          css(ghostEl, 'msTransform', cssMatrix);
          css(ghostEl, 'transform', cssMatrix);
          lastDx = dx;
          lastDy = dy;
          touchEvt = touch;
        }
        evt.cancelable && evt.preventDefault();
      }
    },
    _appendGhost: function _appendGhost() {
      // Bug if using scale(): https://stackoverflow.com/questions/2637058
      // Not being adjusted for
      if (!ghostEl) {
        var container = this.options.fallbackOnBody ? document.body : rootEl,
          rect = getRect(dragEl, true, PositionGhostAbsolutely, true, container),
          options = this.options;

        // Position absolutely
        if (PositionGhostAbsolutely) {
          // Get relatively positioned parent
          ghostRelativeParent = container;
          while (css(ghostRelativeParent, 'position') === 'static' && css(ghostRelativeParent, 'transform') === 'none' && ghostRelativeParent !== document) {
            ghostRelativeParent = ghostRelativeParent.parentNode;
          }
          if (ghostRelativeParent !== document.body && ghostRelativeParent !== document.documentElement) {
            if (ghostRelativeParent === document) ghostRelativeParent = getWindowScrollingElement();
            rect.top += ghostRelativeParent.scrollTop;
            rect.left += ghostRelativeParent.scrollLeft;
          } else {
            ghostRelativeParent = getWindowScrollingElement();
          }
          ghostRelativeParentInitialScroll = getRelativeScrollOffset(ghostRelativeParent);
        }
        ghostEl = dragEl.cloneNode(true);
        toggleClass(ghostEl, options.ghostClass, false);
        toggleClass(ghostEl, options.fallbackClass, true);
        toggleClass(ghostEl, options.dragClass, true);
        css(ghostEl, 'transition', '');
        css(ghostEl, 'transform', '');
        css(ghostEl, 'box-sizing', 'border-box');
        css(ghostEl, 'margin', 0);
        css(ghostEl, 'top', rect.top);
        css(ghostEl, 'left', rect.left);
        css(ghostEl, 'width', rect.width);
        css(ghostEl, 'height', rect.height);
        css(ghostEl, 'opacity', '0.8');
        css(ghostEl, 'position', PositionGhostAbsolutely ? 'absolute' : 'fixed');
        css(ghostEl, 'zIndex', '100000');
        css(ghostEl, 'pointerEvents', 'none');
        Sortable.ghost = ghostEl;
        container.appendChild(ghostEl);

        // Set transform-origin
        css(ghostEl, 'transform-origin', tapDistanceLeft / parseInt(ghostEl.style.width) * 100 + '% ' + tapDistanceTop / parseInt(ghostEl.style.height) * 100 + '%');
      }
    },
    _onDragStart: function _onDragStart( /**Event*/evt, /**boolean*/fallback) {
      var _this = this;
      var dataTransfer = evt.dataTransfer;
      var options = _this.options;
      pluginEvent('dragStart', this, {
        evt: evt
      });
      if (Sortable.eventCanceled) {
        this._onDrop();
        return;
      }
      pluginEvent('setupClone', this);
      if (!Sortable.eventCanceled) {
        cloneEl = clone(dragEl);
        cloneEl.removeAttribute("id");
        cloneEl.draggable = false;
        cloneEl.style['will-change'] = '';
        this._hideClone();
        toggleClass(cloneEl, this.options.chosenClass, false);
        Sortable.clone = cloneEl;
      }

      // #1143: IFrame support workaround
      _this.cloneId = _nextTick(function () {
        pluginEvent('clone', _this);
        if (Sortable.eventCanceled) return;
        if (!_this.options.removeCloneOnHide) {
          rootEl.insertBefore(cloneEl, dragEl);
        }
        _this._hideClone();
        _dispatchEvent({
          sortable: _this,
          name: 'clone'
        });
      });
      !fallback && toggleClass(dragEl, options.dragClass, true);

      // Set proper drop events
      if (fallback) {
        ignoreNextClick = true;
        _this._loopId = setInterval(_this._emulateDragOver, 50);
      } else {
        // Undo what was set in _prepareDragStart before drag started
        off(document, 'mouseup', _this._onDrop);
        off(document, 'touchend', _this._onDrop);
        off(document, 'touchcancel', _this._onDrop);
        if (dataTransfer) {
          dataTransfer.effectAllowed = 'move';
          options.setData && options.setData.call(_this, dataTransfer, dragEl);
        }
        on(document, 'drop', _this);

        // #1276 fix:
        css(dragEl, 'transform', 'translateZ(0)');
      }
      awaitingDragStarted = true;
      _this._dragStartId = _nextTick(_this._dragStarted.bind(_this, fallback, evt));
      on(document, 'selectstart', _this);
      moved = true;
      window.getSelection().removeAllRanges();
      if (Safari) {
        css(document.body, 'user-select', 'none');
      }
    },
    // Returns true - if no further action is needed (either inserted or another condition)
    _onDragOver: function _onDragOver( /**Event*/evt) {
      var el = this.el,
        target = evt.target,
        dragRect,
        targetRect,
        revert,
        options = this.options,
        group = options.group,
        activeSortable = Sortable.active,
        isOwner = activeGroup === group,
        canSort = options.sort,
        fromSortable = putSortable || activeSortable,
        vertical,
        _this = this,
        completedFired = false;
      if (_silent) return;
      function dragOverEvent(name, extra) {
        pluginEvent(name, _this, _objectSpread2({
          evt: evt,
          isOwner: isOwner,
          axis: vertical ? 'vertical' : 'horizontal',
          revert: revert,
          dragRect: dragRect,
          targetRect: targetRect,
          canSort: canSort,
          fromSortable: fromSortable,
          target: target,
          completed: completed,
          onMove: function onMove(target, after) {
            return _onMove(rootEl, el, dragEl, dragRect, target, getRect(target), evt, after);
          },
          changed: changed
        }, extra));
      }

      // Capture animation state
      function capture() {
        dragOverEvent('dragOverAnimationCapture');
        _this.captureAnimationState();
        if (_this !== fromSortable) {
          fromSortable.captureAnimationState();
        }
      }

      // Return invocation when dragEl is inserted (or completed)
      function completed(insertion) {
        dragOverEvent('dragOverCompleted', {
          insertion: insertion
        });
        if (insertion) {
          // Clones must be hidden before folding animation to capture dragRectAbsolute properly
          if (isOwner) {
            activeSortable._hideClone();
          } else {
            activeSortable._showClone(_this);
          }
          if (_this !== fromSortable) {
            // Set ghost class to new sortable's ghost class
            toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : activeSortable.options.ghostClass, false);
            toggleClass(dragEl, options.ghostClass, true);
          }
          if (putSortable !== _this && _this !== Sortable.active) {
            putSortable = _this;
          } else if (_this === Sortable.active && putSortable) {
            putSortable = null;
          }

          // Animation
          if (fromSortable === _this) {
            _this._ignoreWhileAnimating = target;
          }
          _this.animateAll(function () {
            dragOverEvent('dragOverAnimationComplete');
            _this._ignoreWhileAnimating = null;
          });
          if (_this !== fromSortable) {
            fromSortable.animateAll();
            fromSortable._ignoreWhileAnimating = null;
          }
        }

        // Null lastTarget if it is not inside a previously swapped element
        if (target === dragEl && !dragEl.animated || target === el && !target.animated) {
          lastTarget = null;
        }

        // no bubbling and not fallback
        if (!options.dragoverBubble && !evt.rootEl && target !== document) {
          dragEl.parentNode[expando]._isOutsideThisEl(evt.target);

          // Do not detect for empty insert if already inserted
          !insertion && nearestEmptyInsertDetectEvent(evt);
        }
        !options.dragoverBubble && evt.stopPropagation && evt.stopPropagation();
        return completedFired = true;
      }

      // Call when dragEl has been inserted
      function changed() {
        newIndex = index(dragEl);
        newDraggableIndex = index(dragEl, options.draggable);
        _dispatchEvent({
          sortable: _this,
          name: 'change',
          toEl: el,
          newIndex: newIndex,
          newDraggableIndex: newDraggableIndex,
          originalEvent: evt
        });
      }
      if (evt.preventDefault !== void 0) {
        evt.cancelable && evt.preventDefault();
      }
      target = closest(target, options.draggable, el, true);
      dragOverEvent('dragOver');
      if (Sortable.eventCanceled) return completedFired;
      if (dragEl.contains(evt.target) || target.animated && target.animatingX && target.animatingY || _this._ignoreWhileAnimating === target) {
        return completed(false);
      }
      ignoreNextClick = false;
      if (activeSortable && !options.disabled && (isOwner ? canSort || (revert = parentEl !== rootEl) // Reverting item into the original list
      : putSortable === this || (this.lastPutMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) && group.checkPut(this, activeSortable, dragEl, evt))) {
        vertical = this._getDirection(evt, target) === 'vertical';
        dragRect = getRect(dragEl);
        dragOverEvent('dragOverValid');
        if (Sortable.eventCanceled) return completedFired;
        if (revert) {
          parentEl = rootEl; // actualization
          capture();
          this._hideClone();
          dragOverEvent('revert');
          if (!Sortable.eventCanceled) {
            if (nextEl) {
              rootEl.insertBefore(dragEl, nextEl);
            } else {
              rootEl.appendChild(dragEl);
            }
          }
          return completed(true);
        }
        var elLastChild = lastChild(el, options.draggable);
        if (!elLastChild || _ghostIsLast(evt, vertical, this) && !elLastChild.animated) {
          // Insert to end of list

          // If already at end of list: Do not insert
          if (elLastChild === dragEl) {
            return completed(false);
          }

          // if there is a last element, it is the target
          if (elLastChild && el === evt.target) {
            target = elLastChild;
          }
          if (target) {
            targetRect = getRect(target);
          }
          if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, !!target) !== false) {
            capture();
            if (elLastChild && elLastChild.nextSibling) {
              // the last draggable element is not the last node
              el.insertBefore(dragEl, elLastChild.nextSibling);
            } else {
              el.appendChild(dragEl);
            }
            parentEl = el; // actualization

            changed();
            return completed(true);
          }
        } else if (elLastChild && _ghostIsFirst(evt, vertical, this)) {
          // Insert to start of list
          var firstChild = getChild(el, 0, options, true);
          if (firstChild === dragEl) {
            return completed(false);
          }
          target = firstChild;
          targetRect = getRect(target);
          if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, false) !== false) {
            capture();
            el.insertBefore(dragEl, firstChild);
            parentEl = el; // actualization

            changed();
            return completed(true);
          }
        } else if (target.parentNode === el) {
          targetRect = getRect(target);
          var direction = 0,
            targetBeforeFirstSwap,
            differentLevel = dragEl.parentNode !== el,
            differentRowCol = !_dragElInRowColumn(dragEl.animated && dragEl.toRect || dragRect, target.animated && target.toRect || targetRect, vertical),
            side1 = vertical ? 'top' : 'left',
            scrolledPastTop = isScrolledPast(target, 'top', 'top') || isScrolledPast(dragEl, 'top', 'top'),
            scrollBefore = scrolledPastTop ? scrolledPastTop.scrollTop : void 0;
          if (lastTarget !== target) {
            targetBeforeFirstSwap = targetRect[side1];
            pastFirstInvertThresh = false;
            isCircumstantialInvert = !differentRowCol && options.invertSwap || differentLevel;
          }
          direction = _getSwapDirection(evt, target, targetRect, vertical, differentRowCol ? 1 : options.swapThreshold, options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold, isCircumstantialInvert, lastTarget === target);
          var sibling;
          if (direction !== 0) {
            // Check if target is beside dragEl in respective direction (ignoring hidden elements)
            var dragIndex = index(dragEl);
            do {
              dragIndex -= direction;
              sibling = parentEl.children[dragIndex];
            } while (sibling && (css(sibling, 'display') === 'none' || sibling === ghostEl));
          }
          // If dragEl is already beside target: Do not insert
          if (direction === 0 || sibling === target) {
            return completed(false);
          }
          lastTarget = target;
          lastDirection = direction;
          var nextSibling = target.nextElementSibling,
            after = false;
          after = direction === 1;
          var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after);
          if (moveVector !== false) {
            if (moveVector === 1 || moveVector === -1) {
              after = moveVector === 1;
            }
            _silent = true;
            setTimeout(_unsilent, 30);
            capture();
            if (after && !nextSibling) {
              el.appendChild(dragEl);
            } else {
              target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
            }

            // Undo chrome's scroll adjustment (has no effect on other browsers)
            if (scrolledPastTop) {
              scrollBy(scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop);
            }
            parentEl = dragEl.parentNode; // actualization

            // must be done before animation
            if (targetBeforeFirstSwap !== undefined && !isCircumstantialInvert) {
              targetMoveDistance = Math.abs(targetBeforeFirstSwap - getRect(target)[side1]);
            }
            changed();
            return completed(true);
          }
        }
        if (el.contains(dragEl)) {
          return completed(false);
        }
      }
      return false;
    },
    _ignoreWhileAnimating: null,
    _offMoveEvents: function _offMoveEvents() {
      off(document, 'mousemove', this._onTouchMove);
      off(document, 'touchmove', this._onTouchMove);
      off(document, 'pointermove', this._onTouchMove);
      off(document, 'dragover', nearestEmptyInsertDetectEvent);
      off(document, 'mousemove', nearestEmptyInsertDetectEvent);
      off(document, 'touchmove', nearestEmptyInsertDetectEvent);
    },
    _offUpEvents: function _offUpEvents() {
      var ownerDocument = this.el.ownerDocument;
      off(ownerDocument, 'mouseup', this._onDrop);
      off(ownerDocument, 'touchend', this._onDrop);
      off(ownerDocument, 'pointerup', this._onDrop);
      off(ownerDocument, 'pointercancel', this._onDrop);
      off(ownerDocument, 'touchcancel', this._onDrop);
      off(document, 'selectstart', this);
    },
    _onDrop: function _onDrop( /**Event*/evt) {
      var el = this.el,
        options = this.options;

      // Get the index of the dragged element within its parent
      newIndex = index(dragEl);
      newDraggableIndex = index(dragEl, options.draggable);
      pluginEvent('drop', this, {
        evt: evt
      });
      parentEl = dragEl && dragEl.parentNode;

      // Get again after plugin event
      newIndex = index(dragEl);
      newDraggableIndex = index(dragEl, options.draggable);
      if (Sortable.eventCanceled) {
        this._nulling();
        return;
      }
      awaitingDragStarted = false;
      isCircumstantialInvert = false;
      pastFirstInvertThresh = false;
      clearInterval(this._loopId);
      clearTimeout(this._dragStartTimer);
      _cancelNextTick(this.cloneId);
      _cancelNextTick(this._dragStartId);

      // Unbind events
      if (this.nativeDraggable) {
        off(document, 'drop', this);
        off(el, 'dragstart', this._onDragStart);
      }
      this._offMoveEvents();
      this._offUpEvents();
      if (Safari) {
        css(document.body, 'user-select', '');
      }
      css(dragEl, 'transform', '');
      if (evt) {
        if (moved) {
          evt.cancelable && evt.preventDefault();
          !options.dropBubble && evt.stopPropagation();
        }
        ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl);
        if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {
          // Remove clone(s)
          cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl);
        }
        if (dragEl) {
          if (this.nativeDraggable) {
            off(dragEl, 'dragend', this);
          }
          _disableDraggable(dragEl);
          dragEl.style['will-change'] = '';

          // Remove classes
          // ghostClass is added in dragStarted
          if (moved && !awaitingDragStarted) {
            toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : this.options.ghostClass, false);
          }
          toggleClass(dragEl, this.options.chosenClass, false);

          // Drag stop event
          _dispatchEvent({
            sortable: this,
            name: 'unchoose',
            toEl: parentEl,
            newIndex: null,
            newDraggableIndex: null,
            originalEvent: evt
          });
          if (rootEl !== parentEl) {
            if (newIndex >= 0) {
              // Add event
              _dispatchEvent({
                rootEl: parentEl,
                name: 'add',
                toEl: parentEl,
                fromEl: rootEl,
                originalEvent: evt
              });

              // Remove event
              _dispatchEvent({
                sortable: this,
                name: 'remove',
                toEl: parentEl,
                originalEvent: evt
              });

              // drag from one list and drop into another
              _dispatchEvent({
                rootEl: parentEl,
                name: 'sort',
                toEl: parentEl,
                fromEl: rootEl,
                originalEvent: evt
              });
              _dispatchEvent({
                sortable: this,
                name: 'sort',
                toEl: parentEl,
                originalEvent: evt
              });
            }
            putSortable && putSortable.save();
          } else {
            if (newIndex !== oldIndex) {
              if (newIndex >= 0) {
                // drag & drop within the same list
                _dispatchEvent({
                  sortable: this,
                  name: 'update',
                  toEl: parentEl,
                  originalEvent: evt
                });
                _dispatchEvent({
                  sortable: this,
                  name: 'sort',
                  toEl: parentEl,
                  originalEvent: evt
                });
              }
            }
          }
          if (Sortable.active) {
            /* jshint eqnull:true */
            if (newIndex == null || newIndex === -1) {
              newIndex = oldIndex;
              newDraggableIndex = oldDraggableIndex;
            }
            _dispatchEvent({
              sortable: this,
              name: 'end',
              toEl: parentEl,
              originalEvent: evt
            });

            // Save sorting
            this.save();
          }
        }
      }
      this._nulling();
    },
    _nulling: function _nulling() {
      pluginEvent('nulling', this);
      rootEl = dragEl = parentEl = ghostEl = nextEl = cloneEl = lastDownEl = cloneHidden = tapEvt = touchEvt = moved = newIndex = newDraggableIndex = oldIndex = oldDraggableIndex = lastTarget = lastDirection = putSortable = activeGroup = Sortable.dragged = Sortable.ghost = Sortable.clone = Sortable.active = null;
      var el = this.el;
      savedInputChecked.forEach(function (checkEl) {
        if (el.contains(checkEl)) {
          checkEl.checked = true;
        }
      });
      savedInputChecked.length = lastDx = lastDy = 0;
    },
    handleEvent: function handleEvent( /**Event*/evt) {
      switch (evt.type) {
        case 'drop':
        case 'dragend':
          this._onDrop(evt);
          break;
        case 'dragenter':
        case 'dragover':
          if (dragEl) {
            this._onDragOver(evt);
            _globalDragOver(evt);
          }
          break;
        case 'selectstart':
          evt.preventDefault();
          break;
      }
    },
    /**
     * Serializes the item into an array of string.
     * @returns {String[]}
     */
    toArray: function toArray() {
      var order = [],
        el,
        children = this.el.children,
        i = 0,
        n = children.length,
        options = this.options;
      for (; i < n; i++) {
        el = children[i];
        if (closest(el, options.draggable, this.el, false)) {
          order.push(el.getAttribute(options.dataIdAttr) || _generateId(el));
        }
      }
      return order;
    },
    /**
     * Sorts the elements according to the array.
     * @param  {String[]}  order  order of the items
     */
    sort: function sort(order, useAnimation) {
      var items = {},
        rootEl = this.el;
      this.toArray().forEach(function (id, i) {
        var el = rootEl.children[i];
        if (closest(el, this.options.draggable, rootEl, false)) {
          items[id] = el;
        }
      }, this);
      useAnimation && this.captureAnimationState();
      order.forEach(function (id) {
        if (items[id]) {
          rootEl.removeChild(items[id]);
          rootEl.appendChild(items[id]);
        }
      });
      useAnimation && this.animateAll();
    },
    /**
     * Save the current sorting
     */
    save: function save() {
      var store = this.options.store;
      store && store.set && store.set(this);
    },
    /**
     * 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.
     * @param   {HTMLElement}  el
     * @param   {String}       [selector]  default: `options.draggable`
     * @returns {HTMLElement|null}
     */
    closest: function closest$1(el, selector) {
      return closest(el, selector || this.options.draggable, this.el, false);
    },
    /**
     * Set/get option
     * @param   {string} name
     * @param   {*}      [value]
     * @returns {*}
     */
    option: function option(name, value) {
      var options = this.options;
      if (value === void 0) {
        return options[name];
      } else {
        var modifiedValue = PluginManager.modifyOption(this, name, value);
        if (typeof modifiedValue !== 'undefined') {
          options[name] = modifiedValue;
        } else {
          options[name] = value;
        }
        if (name === 'group') {
          _prepareGroup(options);
        }
      }
    },
    /**
     * Destroy
     */
    destroy: function destroy() {
      pluginEvent('destroy', this);
      var el = this.el;
      el[expando] = null;
      off(el, 'mousedown', this._onTapStart);
      off(el, 'touchstart', this._onTapStart);
      off(el, 'pointerdown', this._onTapStart);
      if (this.nativeDraggable) {
        off(el, 'dragover', this);
        off(el, 'dragenter', this);
      }
      // Remove draggable attributes
      Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {
        el.removeAttribute('draggable');
      });
      this._onDrop();
      this._disableDelayedDragEvents();
      sortables.splice(sortables.indexOf(this.el), 1);
      this.el = el = null;
    },
    _hideClone: function _hideClone() {
      if (!cloneHidden) {
        pluginEvent('hideClone', this);
        if (Sortable.eventCanceled) return;
        css(cloneEl, 'display', 'none');
        if (this.options.removeCloneOnHide && cloneEl.parentNode) {
          cloneEl.parentNode.removeChild(cloneEl);
        }
        cloneHidden = true;
      }
    },
    _showClone: function _showClone(putSortable) {
      if (putSortable.lastPutMode !== 'clone') {
        this._hideClone();
        return;
      }
      if (cloneHidden) {
        pluginEvent('showClone', this);
        if (Sortable.eventCanceled) return;

        // show clone at dragEl or original position
        if (dragEl.parentNode == rootEl && !this.options.group.revertClone) {
          rootEl.insertBefore(cloneEl, dragEl);
        } else if (nextEl) {
          rootEl.insertBefore(cloneEl, nextEl);
        } else {
          rootEl.appendChild(cloneEl);
        }
        if (this.options.group.revertClone) {
          this.animate(dragEl, cloneEl);
        }
        css(cloneEl, 'display', '');
        cloneHidden = false;
      }
    }
  };
  function _globalDragOver( /**Event*/evt) {
    if (evt.dataTransfer) {
      evt.dataTransfer.dropEffect = 'move';
    }
    evt.cancelable && evt.preventDefault();
  }
  function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvent, willInsertAfter) {
    var evt,
      sortable = fromEl[expando],
      onMoveFn = sortable.options.onMove,
      retVal;
    // Support for new CustomEvent feature
    if (window.CustomEvent && !IE11OrLess && !Edge) {
      evt = new CustomEvent('move', {
        bubbles: true,
        cancelable: true
      });
    } else {
      evt = document.createEvent('Event');
      evt.initEvent('move', true, true);
    }
    evt.to = toEl;
    evt.from = fromEl;
    evt.dragged = dragEl;
    evt.draggedRect = dragRect;
    evt.related = targetEl || toEl;
    evt.relatedRect = targetRect || getRect(toEl);
    evt.willInsertAfter = willInsertAfter;
    evt.originalEvent = originalEvent;
    fromEl.dispatchEvent(evt);
    if (onMoveFn) {
      retVal = onMoveFn.call(sortable, evt, originalEvent);
    }
    return retVal;
  }
  function _disableDraggable(el) {
    el.draggable = false;
  }
  function _unsilent() {
    _silent = false;
  }
  function _ghostIsFirst(evt, vertical, sortable) {
    var firstElRect = getRect(getChild(sortable.el, 0, sortable.options, true));
    var childContainingRect = getChildContainingRectFromElement(sortable.el, sortable.options, ghostEl);
    var spacer = 10;
    return vertical ? evt.clientX < childContainingRect.left - spacer || evt.clientY < firstElRect.top && evt.clientX < firstElRect.right : evt.clientY < childContainingRect.top - spacer || evt.clientY < firstElRect.bottom && evt.clientX < firstElRect.left;
  }
  function _ghostIsLast(evt, vertical, sortable) {
    var lastElRect = getRect(lastChild(sortable.el, sortable.options.draggable));
    var childContainingRect = getChildContainingRectFromElement(sortable.el, sortable.options, ghostEl);
    var spacer = 10;
    return vertical ? evt.clientX > childContainingRect.right + spacer || evt.clientY > lastElRect.bottom && evt.clientX > lastElRect.left : evt.clientY > childContainingRect.bottom + spacer || evt.clientX > lastElRect.right && evt.clientY > lastElRect.top;
  }
  function _getSwapDirection(evt, target, targetRect, vertical, swapThreshold, invertedSwapThreshold, invertSwap, isLastTarget) {
    var mouseOnAxis = vertical ? evt.clientY : evt.clientX,
      targetLength = vertical ? targetRect.height : targetRect.width,
      targetS1 = vertical ? targetRect.top : targetRect.left,
      targetS2 = vertical ? targetRect.bottom : targetRect.right,
      invert = false;
    if (!invertSwap) {
      // Never invert or create dragEl shadow when target movemenet causes mouse to move past the end of regular swapThreshold
      if (isLastTarget && targetMoveDistance < targetLength * swapThreshold) {
        // multiplied only by swapThreshold because mouse will already be inside target by (1 - threshold) * targetLength / 2
        // check if past first invert threshold on side opposite of lastDirection
        if (!pastFirstInvertThresh && (lastDirection === 1 ? mouseOnAxis > targetS1 + targetLength * invertedSwapThreshold / 2 : mouseOnAxis < targetS2 - targetLength * invertedSwapThreshold / 2)) {
          // past first invert threshold, do not restrict inverted threshold to dragEl shadow
          pastFirstInvertThresh = true;
        }
        if (!pastFirstInvertThresh) {
          // dragEl shadow (target move distance shadow)
          if (lastDirection === 1 ? mouseOnAxis < targetS1 + targetMoveDistance // over dragEl shadow
          : mouseOnAxis > targetS2 - targetMoveDistance) {
            return -lastDirection;
          }
        } else {
          invert = true;
        }
      } else {
        // Regular
        if (mouseOnAxis > targetS1 + targetLength * (1 - swapThreshold) / 2 && mouseOnAxis < targetS2 - targetLength * (1 - swapThreshold) / 2) {
          return _getInsertDirection(target);
        }
      }
    }
    invert = invert || invertSwap;
    if (invert) {
      // Invert of regular
      if (mouseOnAxis < targetS1 + targetLength * invertedSwapThreshold / 2 || mouseOnAxis > targetS2 - targetLength * invertedSwapThreshold / 2) {
        return mouseOnAxis > targetS1 + targetLength / 2 ? 1 : -1;
      }
    }
    return 0;
  }

  /**
   * Gets the direction dragEl must be swapped relative to target in order to make it
   * seem that dragEl has been "inserted" into that element's position
   * @param  {HTMLElement} target       The target whose position dragEl is being inserted at
   * @return {Number}                   Direction dragEl must be swapped
   */
  function _getInsertDirection(target) {
    if (index(dragEl) < index(target)) {
      return 1;
    } else {
      return -1;
    }
  }

  /**
   * Generate id
   * @param   {HTMLElement} el
   * @returns {String}
   * @private
   */
  function _generateId(el) {
    var str = el.tagName + el.className + el.src + el.href + el.textContent,
      i = str.length,
      sum = 0;
    while (i--) {
      sum += str.charCodeAt(i);
    }
    return sum.toString(36);
  }
  function _saveInputCheckedState(root) {
    savedInputChecked.length = 0;
    var inputs = root.getElementsByTagName('input');
    var idx = inputs.length;
    while (idx--) {
      var el = inputs[idx];
      el.checked && savedInputChecked.push(el);
    }
  }
  function _nextTick(fn) {
    return setTimeout(fn, 0);
  }
  function _cancelNextTick(id) {
    return clearTimeout(id);
  }

  // Fixed #973:
  if (documentExists) {
    on(document, 'touchmove', function (evt) {
      if ((Sortable.active || awaitingDragStarted) && evt.cancelable) {
        evt.preventDefault();
      }
    });
  }

  // Export utils
  Sortable.utils = {
    on: on,
    off: off,
    css: css,
    find: find,
    is: function is(el, selector) {
      return !!closest(el, selector, el, false);
    },
    extend: extend,
    throttle: throttle,
    closest: closest,
    toggleClass: toggleClass,
    clone: clone,
    index: index,
    nextTick: _nextTick,
    cancelNextTick: _cancelNextTick,
    detectDirection: _detectDirection,
    getChild: getChild,
    expando: expando
  };

  /**
   * Get the Sortable instance of an element
   * @param  {HTMLElement} element The element
   * @return {Sortable|undefined}         The instance of Sortable
   */
  Sortable.get = function (element) {
    return element[expando];
  };

  /**
   * Mount a plugin to Sortable
   * @param  {...SortablePlugin|SortablePlugin[]} plugins       Plugins being mounted
   */
  Sortable.mount = function () {
    for (var _len = arguments.length, plugins = new Array(_len), _key = 0; _key < _len; _key++) {
      plugins[_key] = arguments[_key];
    }
    if (plugins[0].constructor === Array) plugins = plugins[0];
    plugins.forEach(function (plugin) {
      if (!plugin.prototype || !plugin.prototype.constructor) {
        throw "Sortable: Mounted plugin must be a constructor function, not ".concat({}.toString.call(plugin));
      }
      if (plugin.utils) Sortable.utils = _objectSpread2(_objectSpread2({}, Sortable.utils), plugin.utils);
      PluginManager.mount(plugin);
    });
  };

  /**
   * Create sortable instance
   * @param {HTMLElement}  el
   * @param {Object}      [options]
   */
  Sortable.create = function (el, options) {
    return new Sortable(el, options);
  };

  // Export
  Sortable.version = version;

  var autoScrolls = [],
    scrollEl,
    scrollRootEl,
    scrolling = false,
    lastAutoScrollX,
    lastAutoScrollY,
    touchEvt$1,
    pointerElemChangedInterval;
  function AutoScrollPlugin() {
    function AutoScroll() {
      this.defaults = {
        scroll: true,
        forceAutoScrollFallback: false,
        scrollSensitivity: 30,
        scrollSpeed: 10,
        bubbleScroll: true
      };

      // Bind all private methods
      for (var fn in this) {
        if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
          this[fn] = this[fn].bind(this);
        }
      }
    }
    AutoScroll.prototype = {
      dragStarted: function dragStarted(_ref) {
        var originalEvent = _ref.originalEvent;
        if (this.sortable.nativeDraggable) {
          on(document, 'dragover', this._handleAutoScroll);
        } else {
          if (this.options.supportPointer) {
            on(document, 'pointermove', this._handleFallbackAutoScroll);
          } else if (originalEvent.touches) {
            on(document, 'touchmove', this._handleFallbackAutoScroll);
          } else {
            on(document, 'mousemove', this._handleFallbackAutoScroll);
          }
        }
      },
      dragOverCompleted: function dragOverCompleted(_ref2) {
        var originalEvent = _ref2.originalEvent;
        // For when bubbling is canceled and using fallback (fallback 'touchmove' always reached)
        if (!this.options.dragOverBubble && !originalEvent.rootEl) {
          this._handleAutoScroll(originalEvent);
        }
      },
      drop: function drop() {
        if (this.sortable.nativeDraggable) {
          off(document, 'dragover', this._handleAutoScroll);
        } else {
          off(document, 'pointermove', this._handleFallbackAutoScroll);
          off(document, 'touchmove', this._handleFallbackAutoScroll);
          off(document, 'mousemove', this._handleFallbackAutoScroll);
        }
        clearPointerElemChangedInterval();
        clearAutoScrolls();
        cancelThrottle();
      },
      nulling: function nulling() {
        touchEvt$1 = scrollRootEl = scrollEl = scrolling = pointerElemChangedInterval = lastAutoScrollX = lastAutoScrollY = null;
        autoScrolls.length = 0;
      },
      _handleFallbackAutoScroll: function _handleFallbackAutoScroll(evt) {
        this._handleAutoScroll(evt, true);
      },
      _handleAutoScroll: function _handleAutoScroll(evt, fallback) {
        var _this = this;
        var x = (evt.touches ? evt.touches[0] : evt).clientX,
          y = (evt.touches ? evt.touches[0] : evt).clientY,
          elem = document.elementFromPoint(x, y);
        touchEvt$1 = evt;

        // IE does not seem to have native autoscroll,
        // Edge's autoscroll seems too conditional,
        // MACOS Safari does not have autoscroll,
        // Firefox and Chrome are good
        if (fallback || this.options.forceAutoScrollFallback || Edge || IE11OrLess || Safari) {
          autoScroll(evt, this.options, elem, fallback);

          // Listener for pointer element change
          var ogElemScroller = getParentAutoScrollElement(elem, true);
          if (scrolling && (!pointerElemChangedInterval || x !== lastAutoScrollX || y !== lastAutoScrollY)) {
            pointerElemChangedInterval && clearPointerElemChangedInterval();
            // Detect for pointer elem change, emulating native DnD behaviour
            pointerElemChangedInterval = setInterval(function () {
              var newElem = getParentAutoScrollElement(document.elementFromPoint(x, y), true);
              if (newElem !== ogElemScroller) {
                ogElemScroller = newElem;
                clearAutoScrolls();
              }
              autoScroll(evt, _this.options, newElem, fallback);
            }, 10);
            lastAutoScrollX = x;
            lastAutoScrollY = y;
          }
        } else {
          // if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll
          if (!this.options.bubbleScroll || getParentAutoScrollElement(elem, true) === getWindowScrollingElement()) {
            clearAutoScrolls();
            return;
          }
          autoScroll(evt, this.options, getParentAutoScrollElement(elem, false), false);
        }
      }
    };
    return _extends(AutoScroll, {
      pluginName: 'scroll',
      initializeByDefault: true
    });
  }
  function clearAutoScrolls() {
    autoScrolls.forEach(function (autoScroll) {
      clearInterval(autoScroll.pid);
    });
    autoScrolls = [];
  }
  function clearPointerElemChangedInterval() {
    clearInterval(pointerElemChangedInterval);
  }
  var autoScroll = throttle(function (evt, options, rootEl, isFallback) {
    // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
    if (!options.scroll) return;
    var x = (evt.touches ? evt.touches[0] : evt).clientX,
      y = (evt.touches ? evt.touches[0] : evt).clientY,
      sens = options.scrollSensitivity,
      speed = options.scrollSpeed,
      winScroller = getWindowScrollingElement();
    var scrollThisInstance = false,
      scrollCustomFn;

    // New scroll root, set scrollEl
    if (scrollRootEl !== rootEl) {
      scrollRootEl = rootEl;
      clearAutoScrolls();
      scrollEl = options.scroll;
      scrollCustomFn = options.scrollFn;
      if (scrollEl === true) {
        scrollEl = getParentAutoScrollElement(rootEl, true);
      }
    }
    var layersOut = 0;
    var currentParent = scrollEl;
    do {
      var el = currentParent,
        rect = getRect(el),
        top = rect.top,
        bottom = rect.bottom,
        left = rect.left,
        right = rect.right,
        width = rect.width,
        height = rect.height,
        canScrollX = void 0,
        canScrollY = void 0,
        scrollWidth = el.scrollWidth,
        scrollHeight = el.scrollHeight,
        elCSS = css(el),
        scrollPosX = el.scrollLeft,
        scrollPosY = el.scrollTop;
      if (el === winScroller) {
        canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll' || elCSS.overflowX === 'visible');
        canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll' || elCSS.overflowY === 'visible');
      } else {
        canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll');
        canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll');
      }
      var vx = canScrollX && (Math.abs(right - x) <= sens && scrollPosX + width < scrollWidth) - (Math.abs(left - x) <= sens && !!scrollPosX);
      var vy = canScrollY && (Math.abs(bottom - y) <= sens && scrollPosY + height < scrollHeight) - (Math.abs(top - y) <= sens && !!scrollPosY);
      if (!autoScrolls[layersOut]) {
        for (var i = 0; i <= layersOut; i++) {
          if (!autoScrolls[i]) {
            autoScrolls[i] = {};
          }
        }
      }
      if (autoScrolls[layersOut].vx != vx || autoScrolls[layersOut].vy != vy || autoScrolls[layersOut].el !== el) {
        autoScrolls[layersOut].el = el;
        autoScrolls[layersOut].vx = vx;
        autoScrolls[layersOut].vy = vy;
        clearInterval(autoScrolls[layersOut].pid);
        if (vx != 0 || vy != 0) {
          scrollThisInstance = true;
          /* jshint loopfunc:true */
          autoScrolls[layersOut].pid = setInterval(function () {
            // emulate drag over during autoscroll (fallback), emulating native DnD behaviour
            if (isFallback && this.layer === 0) {
              Sortable.active._onTouchMove(touchEvt$1); // To move ghost if it is positioned absolutely
            }
            var scrollOffsetY = autoScrolls[this.layer].vy ? autoScrolls[this.layer].vy * speed : 0;
            var scrollOffsetX = autoScrolls[this.layer].vx ? autoScrolls[this.layer].vx * speed : 0;
            if (typeof scrollCustomFn === 'function') {
              if (scrollCustomFn.call(Sortable.dragged.parentNode[expando], scrollOffsetX, scrollOffsetY, evt, touchEvt$1, autoScrolls[this.layer].el) !== 'continue') {
                return;
              }
            }
            scrollBy(autoScrolls[this.layer].el, scrollOffsetX, scrollOffsetY);
          }.bind({
            layer: layersOut
          }), 24);
        }
      }
      layersOut++;
    } while (options.bubbleScroll && currentParent !== winScroller && (currentParent = getParentAutoScrollElement(currentParent, false)));
    scrolling = scrollThisInstance; // in case another function catches scrolling as false in between when it is not
  }, 30);

  var drop = function drop(_ref) {
    var originalEvent = _ref.originalEvent,
      putSortable = _ref.putSortable,
      dragEl = _ref.dragEl,
      activeSortable = _ref.activeSortable,
      dispatchSortableEvent = _ref.dispatchSortableEvent,
      hideGhostForTarget = _ref.hideGhostForTarget,
      unhideGhostForTarget = _ref.unhideGhostForTarget;
    if (!originalEvent) return;
    var toSortable = putSortable || activeSortable;
    hideGhostForTarget();
    var touch = originalEvent.changedTouches && originalEvent.changedTouches.length ? originalEvent.changedTouches[0] : originalEvent;
    var target = document.elementFromPoint(touch.clientX, touch.clientY);
    unhideGhostForTarget();
    if (toSortable && !toSortable.el.contains(target)) {
      dispatchSortableEvent('spill');
      this.onSpill({
        dragEl: dragEl,
        putSortable: putSortable
      });
    }
  };
  function Revert() {}
  Revert.prototype = {
    startIndex: null,
    dragStart: function dragStart(_ref2) {
      var oldDraggableIndex = _ref2.oldDraggableIndex;
      this.startIndex = oldDraggableIndex;
    },
    onSpill: function onSpill(_ref3) {
      var dragEl = _ref3.dragEl,
        putSortable = _ref3.putSortable;
      this.sortable.captureAnimationState();
      if (putSortable) {
        putSortable.captureAnimationState();
      }
      var nextSibling = getChild(this.sortable.el, this.startIndex, this.options);
      if (nextSibling) {
        this.sortable.el.insertBefore(dragEl, nextSibling);
      } else {
        this.sortable.el.appendChild(dragEl);
      }
      this.sortable.animateAll();
      if (putSortable) {
        putSortable.animateAll();
      }
    },
    drop: drop
  };
  _extends(Revert, {
    pluginName: 'revertOnSpill'
  });
  function Remove() {}
  Remove.prototype = {
    onSpill: function onSpill(_ref4) {
      var dragEl = _ref4.dragEl,
        putSortable = _ref4.putSortable;
      var parentSortable = putSortable || this.sortable;
      parentSortable.captureAnimationState();
      dragEl.parentNode && dragEl.parentNode.removeChild(dragEl);
      parentSortable.animateAll();
    },
    drop: drop
  };
  _extends(Remove, {
    pluginName: 'removeOnSpill'
  });

  var lastSwapEl;
  function SwapPlugin() {
    function Swap() {
      this.defaults = {
        swapClass: 'sortable-swap-highlight'
      };
    }
    Swap.prototype = {
      dragStart: function dragStart(_ref) {
        var dragEl = _ref.dragEl;
        lastSwapEl = dragEl;
      },
      dragOverValid: function dragOverValid(_ref2) {
        var completed = _ref2.completed,
          target = _ref2.target,
          onMove = _ref2.onMove,
          activeSortable = _ref2.activeSortable,
          changed = _ref2.changed,
          cancel = _ref2.cancel;
        if (!activeSortable.options.swap) return;
        var el = this.sortable.el,
          options = this.options;
        if (target && target !== el) {
          var prevSwapEl = lastSwapEl;
          if (onMove(target) !== false) {
            toggleClass(target, options.swapClass, true);
            lastSwapEl = target;
          } else {
            lastSwapEl = null;
          }
          if (prevSwapEl && prevSwapEl !== lastSwapEl) {
            toggleClass(prevSwapEl, options.swapClass, false);
          }
        }
        changed();
        completed(true);
        cancel();
      },
      drop: function drop(_ref3) {
        var activeSortable = _ref3.activeSortable,
          putSortable = _ref3.putSortable,
          dragEl = _ref3.dragEl;
        var toSortable = putSortable || this.sortable;
        var options = this.options;
        lastSwapEl && toggleClass(lastSwapEl, options.swapClass, false);
        if (lastSwapEl && (options.swap || putSortable && putSortable.options.swap)) {
          if (dragEl !== lastSwapEl) {
            toSortable.captureAnimationState();
            if (toSortable !== activeSortable) activeSortable.captureAnimationState();
            swapNodes(dragEl, lastSwapEl);
            toSortable.animateAll();
            if (toSortable !== activeSortable) activeSortable.animateAll();
          }
        }
      },
      nulling: function nulling() {
        lastSwapEl = null;
      }
    };
    return _extends(Swap, {
      pluginName: 'swap',
      eventProperties: function eventProperties() {
        return {
          swapItem: lastSwapEl
        };
      }
    });
  }
  function swapNodes(n1, n2) {
    var p1 = n1.parentNode,
      p2 = n2.parentNode,
      i1,
      i2;
    if (!p1 || !p2 || p1.isEqualNode(n2) || p2.isEqualNode(n1)) return;
    i1 = index(n1);
    i2 = index(n2);
    if (p1.isEqualNode(p2) && i1 < i2) {
      i2++;
    }
    p1.insertBefore(n2, p1.children[i1]);
    p2.insertBefore(n1, p2.children[i2]);
  }

  var multiDragElements = [],
    multiDragClones = [],
    lastMultiDragSelect,
    // for selection with modifier key down (SHIFT)
    multiDragSortable,
    initialFolding = false,
    // Initial multi-drag fold when drag started
    folding = false,
    // Folding any other time
    dragStarted = false,
    dragEl$1,
    clonesFromRect,
    clonesHidden;
  function MultiDragPlugin() {
    function MultiDrag(sortable) {
      // Bind all private methods
      for (var fn in this) {
        if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
          this[fn] = this[fn].bind(this);
        }
      }
      if (!sortable.options.avoidImplicitDeselect) {
        if (sortable.options.supportPointer) {
          on(document, 'pointerup', this._deselectMultiDrag);
        } else {
          on(document, 'mouseup', this._deselectMultiDrag);
          on(document, 'touchend', this._deselectMultiDrag);
        }
      }
      on(document, 'keydown', this._checkKeyDown);
      on(document, 'keyup', this._checkKeyUp);
      this.defaults = {
        selectedClass: 'sortable-selected',
        multiDragKey: null,
        avoidImplicitDeselect: false,
        setData: function setData(dataTransfer, dragEl) {
          var data = '';
          if (multiDragElements.length && multiDragSortable === sortable) {
            multiDragElements.forEach(function (multiDragElement, i) {
              data += (!i ? '' : ', ') + multiDragElement.textContent;
            });
          } else {
            data = dragEl.textContent;
          }
          dataTransfer.setData('Text', data);
        }
      };
    }
    MultiDrag.prototype = {
      multiDragKeyDown: false,
      isMultiDrag: false,
      delayStartGlobal: function delayStartGlobal(_ref) {
        var dragged = _ref.dragEl;
        dragEl$1 = dragged;
      },
      delayEnded: function delayEnded() {
        this.isMultiDrag = ~multiDragElements.indexOf(dragEl$1);
      },
      setupClone: function setupClone(_ref2) {
        var sortable = _ref2.sortable,
          cancel = _ref2.cancel;
        if (!this.isMultiDrag) return;
        for (var i = 0; i < multiDragElements.length; i++) {
          multiDragClones.push(clone(multiDragElements[i]));
          multiDragClones[i].sortableIndex = multiDragElements[i].sortableIndex;
          multiDragClones[i].draggable = false;
          multiDragClones[i].style['will-change'] = '';
          toggleClass(multiDragClones[i], this.options.selectedClass, false);
          multiDragElements[i] === dragEl$1 && toggleClass(multiDragClones[i], this.options.chosenClass, false);
        }
        sortable._hideClone();
        cancel();
      },
      clone: function clone(_ref3) {
        var sortable = _ref3.sortable,
          rootEl = _ref3.rootEl,
          dispatchSortableEvent = _ref3.dispatchSortableEvent,
          cancel = _ref3.cancel;
        if (!this.isMultiDrag) return;
        if (!this.options.removeCloneOnHide) {
          if (multiDragElements.length && multiDragSortable === sortable) {
            insertMultiDragClones(true, rootEl);
            dispatchSortableEvent('clone');
            cancel();
          }
        }
      },
      showClone: function showClone(_ref4) {
        var cloneNowShown = _ref4.cloneNowShown,
          rootEl = _ref4.rootEl,
          cancel = _ref4.cancel;
        if (!this.isMultiDrag) return;
        insertMultiDragClones(false, rootEl);
        multiDragClones.forEach(function (clone) {
          css(clone, 'display', '');
        });
        cloneNowShown();
        clonesHidden = false;
        cancel();
      },
      hideClone: function hideClone(_ref5) {
        var _this = this;
        var sortable = _ref5.sortable,
          cloneNowHidden = _ref5.cloneNowHidden,
          cancel = _ref5.cancel;
        if (!this.isMultiDrag) return;
        multiDragClones.forEach(function (clone) {
          css(clone, 'display', 'none');
          if (_this.options.removeCloneOnHide && clone.parentNode) {
            clone.parentNode.removeChild(clone);
          }
        });
        cloneNowHidden();
        clonesHidden = true;
        cancel();
      },
      dragStartGlobal: function dragStartGlobal(_ref6) {
        var sortable = _ref6.sortable;
        if (!this.isMultiDrag && multiDragSortable) {
          multiDragSortable.multiDrag._deselectMultiDrag();
        }
        multiDragElements.forEach(function (multiDragElement) {
          multiDragElement.sortableIndex = index(multiDragElement);
        });

        // Sort multi-drag elements
        multiDragElements = multiDragElements.sort(function (a, b) {
          return a.sortableIndex - b.sortableIndex;
        });
        dragStarted = true;
      },
      dragStarted: function dragStarted(_ref7) {
        var _this2 = this;
        var sortable = _ref7.sortable;
        if (!this.isMultiDrag) return;
        if (this.options.sort) {
          // Capture rects,
          // hide multi drag elements (by positioning them absolute),
          // set multi drag elements rects to dragRect,
          // show multi drag elements,
          // animate to rects,
          // unset rects & remove from DOM

          sortable.captureAnimationState();
          if (this.options.animation) {
            multiDragElements.forEach(function (multiDragElement) {
              if (multiDragElement === dragEl$1) return;
              css(multiDragElement, 'position', 'absolute');
            });
            var dragRect = getRect(dragEl$1, false, true, true);
            multiDragElements.forEach(function (multiDragElement) {
              if (multiDragElement === dragEl$1) return;
              setRect(multiDragElement, dragRect);
            });
            folding = true;
            initialFolding = true;
          }
        }
        sortable.animateAll(function () {
          folding = false;
          initialFolding = false;
          if (_this2.options.animation) {
            multiDragElements.forEach(function (multiDragElement) {
              unsetRect(multiDragElement);
            });
          }

          // Remove all auxiliary multidrag items from el, if sorting enabled
          if (_this2.options.sort) {
            removeMultiDragElements();
          }
        });
      },
      dragOver: function dragOver(_ref8) {
        var target = _ref8.target,
          completed = _ref8.completed,
          cancel = _ref8.cancel;
        if (folding && ~multiDragElements.indexOf(target)) {
          completed(false);
          cancel();
        }
      },
      revert: function revert(_ref9) {
        var fromSortable = _ref9.fromSortable,
          rootEl = _ref9.rootEl,
          sortable = _ref9.sortable,
          dragRect = _ref9.dragRect;
        if (multiDragElements.length > 1) {
          // Setup unfold animation
          multiDragElements.forEach(function (multiDragElement) {
            sortable.addAnimationState({
              target: multiDragElement,
              rect: folding ? getRect(multiDragElement) : dragRect
            });
            unsetRect(multiDragElement);
            multiDragElement.fromRect = dragRect;
            fromSortable.removeAnimationState(multiDragElement);
          });
          folding = false;
          insertMultiDragElements(!this.options.removeCloneOnHide, rootEl);
        }
      },
      dragOverCompleted: function dragOverCompleted(_ref10) {
        var sortable = _ref10.sortable,
          isOwner = _ref10.isOwner,
          insertion = _ref10.insertion,
          activeSortable = _ref10.activeSortable,
          parentEl = _ref10.parentEl,
          putSortable = _ref10.putSortable;
        var options = this.options;
        if (insertion) {
          // Clones must be hidden before folding animation to capture dragRectAbsolute properly
          if (isOwner) {
            activeSortable._hideClone();
          }
          initialFolding = false;
          // If leaving sort:false root, or already folding - Fold to new location
          if (options.animation && multiDragElements.length > 1 && (folding || !isOwner && !activeSortable.options.sort && !putSortable)) {
            // Fold: Set all multi drag elements's rects to dragEl's rect when multi-drag elements are invisible
            var dragRectAbsolute = getRect(dragEl$1, false, true, true);
            multiDragElements.forEach(function (multiDragElement) {
              if (multiDragElement === dragEl$1) return;
              setRect(multiDragElement, dragRectAbsolute);

              // Move element(s) to end of parentEl so that it does not interfere with multi-drag clones insertion if they are inserted
              // while folding, and so that we can capture them again because old sortable will no longer be fromSortable
              parentEl.appendChild(multiDragElement);
            });
            folding = true;
          }

          // Clones must be shown (and check to remove multi drags) after folding when interfering multiDragElements are moved out
          if (!isOwner) {
            // Only remove if not folding (folding will remove them anyways)
            if (!folding) {
              removeMultiDragElements();
            }
            if (multiDragElements.length > 1) {
              var clonesHiddenBefore = clonesHidden;
              activeSortable._showClone(sortable);

              // Unfold animation for clones if showing from hidden
              if (activeSortable.options.animation && !clonesHidden && clonesHiddenBefore) {
                multiDragClones.forEach(function (clone) {
                  activeSortable.addAnimationState({
                    target: clone,
                    rect: clonesFromRect
                  });
                  clone.fromRect = clonesFromRect;
                  clone.thisAnimationDuration = null;
                });
              }
            } else {
              activeSortable._showClone(sortable);
            }
          }
        }
      },
      dragOverAnimationCapture: function dragOverAnimationCapture(_ref11) {
        var dragRect = _ref11.dragRect,
          isOwner = _ref11.isOwner,
          activeSortable = _ref11.activeSortable;
        multiDragElements.forEach(function (multiDragElement) {
          multiDragElement.thisAnimationDuration = null;
        });
        if (activeSortable.options.animation && !isOwner && activeSortable.multiDrag.isMultiDrag) {
          clonesFromRect = _extends({}, dragRect);
          var dragMatrix = matrix(dragEl$1, true);
          clonesFromRect.top -= dragMatrix.f;
          clonesFromRect.left -= dragMatrix.e;
        }
      },
      dragOverAnimationComplete: function dragOverAnimationComplete() {
        if (folding) {
          folding = false;
          removeMultiDragElements();
        }
      },
      drop: function drop(_ref12) {
        var evt = _ref12.originalEvent,
          rootEl = _ref12.rootEl,
          parentEl = _ref12.parentEl,
          sortable = _ref12.sortable,
          dispatchSortableEvent = _ref12.dispatchSortableEvent,
          oldIndex = _ref12.oldIndex,
          putSortable = _ref12.putSortable;
        var toSortable = putSortable || this.sortable;
        if (!evt) return;
        var options = this.options,
          children = parentEl.children;

        // Multi-drag selection
        if (!dragStarted) {
          if (options.multiDragKey && !this.multiDragKeyDown) {
            this._deselectMultiDrag();
          }
          toggleClass(dragEl$1, options.selectedClass, !~multiDragElements.indexOf(dragEl$1));
          if (!~multiDragElements.indexOf(dragEl$1)) {
            multiDragElements.push(dragEl$1);
            dispatchEvent({
              sortable: sortable,
              rootEl: rootEl,
              name: 'select',
              targetEl: dragEl$1,
              originalEvent: evt
            });

            // Modifier activated, select from last to dragEl
            if (evt.shiftKey && lastMultiDragSelect && sortable.el.contains(lastMultiDragSelect)) {
              var lastIndex = index(lastMultiDragSelect),
                currentIndex = index(dragEl$1);
              if (~lastIndex && ~currentIndex && lastIndex !== currentIndex) {
                (function () {
                  // Must include lastMultiDragSelect (select it), in case modified selection from no selection
                  // (but previous selection existed)
                  var n, i;
                  if (currentIndex > lastIndex) {
                    i = lastIndex;
                    n = currentIndex;
                  } else {
                    i = currentIndex;
                    n = lastIndex + 1;
                  }
                  var filter = options.filter;
                  for (; i < n; i++) {
                    if (~multiDragElements.indexOf(children[i])) continue;
                    // Check if element is draggable
                    if (!closest(children[i], options.draggable, parentEl, false)) continue;
                    // Check if element is filtered
                    var filtered = filter && (typeof filter === 'function' ? filter.call(sortable, evt, children[i], sortable) : filter.split(',').some(function (criteria) {
                      return closest(children[i], criteria.trim(), parentEl, false);
                    }));
                    if (filtered) continue;
                    toggleClass(children[i], options.selectedClass, true);
                    multiDragElements.push(children[i]);
                    dispatchEvent({
                      sortable: sortable,
                      rootEl: rootEl,
                      name: 'select',
                      targetEl: children[i],
                      originalEvent: evt
                    });
                  }
                })();
              }
            } else {
              lastMultiDragSelect = dragEl$1;
            }
            multiDragSortable = toSortable;
          } else {
            multiDragElements.splice(multiDragElements.indexOf(dragEl$1), 1);
            lastMultiDragSelect = null;
            dispatchEvent({
              sortable: sortable,
              rootEl: rootEl,
              name: 'deselect',
              targetEl: dragEl$1,
              originalEvent: evt
            });
          }
        }

        // Multi-drag drop
        if (dragStarted && this.isMultiDrag) {
          folding = false;
          // Do not "unfold" after around dragEl if reverted
          if ((parentEl[expando].options.sort || parentEl !== rootEl) && multiDragElements.length > 1) {
            var dragRect = getRect(dragEl$1),
              multiDragIndex = index(dragEl$1, ':not(.' + this.options.selectedClass + ')');
            if (!initialFolding && options.animation) dragEl$1.thisAnimationDuration = null;
            toSortable.captureAnimationState();
            if (!initialFolding) {
              if (options.animation) {
                dragEl$1.fromRect = dragRect;
                multiDragElements.forEach(function (multiDragElement) {
                  multiDragElement.thisAnimationDuration = null;
                  if (multiDragElement !== dragEl$1) {
                    var rect = folding ? getRect(multiDragElement) : dragRect;
                    multiDragElement.fromRect = rect;

                    // Prepare unfold animation
                    toSortable.addAnimationState({
                      target: multiDragElement,
                      rect: rect
                    });
                  }
                });
              }

              // Multi drag elements are not necessarily removed from the DOM on drop, so to reinsert
              // properly they must all be removed
              removeMultiDragElements();
              multiDragElements.forEach(function (multiDragElement) {
                if (children[multiDragIndex]) {
                  parentEl.insertBefore(multiDragElement, children[multiDragIndex]);
                } else {
                  parentEl.appendChild(multiDragElement);
                }
                multiDragIndex++;
              });

              // If initial folding is done, the elements may have changed position because they are now
              // unfolding around dragEl, even though dragEl may not have his index changed, so update event
              // must be fired here as Sortable will not.
              if (oldIndex === index(dragEl$1)) {
                var update = false;
                multiDragElements.forEach(function (multiDragElement) {
                  if (multiDragElement.sortableIndex !== index(multiDragElement)) {
                    update = true;
                    return;
                  }
                });
                if (update) {
                  dispatchSortableEvent('update');
                  dispatchSortableEvent('sort');
                }
              }
            }

            // Must be done after capturing individual rects (scroll bar)
            multiDragElements.forEach(function (multiDragElement) {
              unsetRect(multiDragElement);
            });
            toSortable.animateAll();
          }
          multiDragSortable = toSortable;
        }

        // Remove clones if necessary
        if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {
          multiDragClones.forEach(function (clone) {
            clone.parentNode && clone.parentNode.removeChild(clone);
          });
        }
      },
      nullingGlobal: function nullingGlobal() {
        this.isMultiDrag = dragStarted = false;
        multiDragClones.length = 0;
      },
      destroyGlobal: function destroyGlobal() {
        this._deselectMultiDrag();
        off(document, 'pointerup', this._deselectMultiDrag);
        off(document, 'mouseup', this._deselectMultiDrag);
        off(document, 'touchend', this._deselectMultiDrag);
        off(document, 'keydown', this._checkKeyDown);
        off(document, 'keyup', this._checkKeyUp);
      },
      _deselectMultiDrag: function _deselectMultiDrag(evt) {
        if (typeof dragStarted !== "undefined" && dragStarted) return;

        // Only deselect if selection is in this sortable
        if (multiDragSortable !== this.sortable) return;

        // Only deselect if target is not item in this sortable
        if (evt && closest(evt.target, this.options.draggable, this.sortable.el, false)) return;

        // Only deselect if left click
        if (evt && evt.button !== 0) return;
        while (multiDragElements.length) {
          var el = multiDragElements[0];
          toggleClass(el, this.options.selectedClass, false);
          multiDragElements.shift();
          dispatchEvent({
            sortable: this.sortable,
            rootEl: this.sortable.el,
            name: 'deselect',
            targetEl: el,
            originalEvent: evt
          });
        }
      },
      _checkKeyDown: function _checkKeyDown(evt) {
        if (evt.key === this.options.multiDragKey) {
          this.multiDragKeyDown = true;
        }
      },
      _checkKeyUp: function _checkKeyUp(evt) {
        if (evt.key === this.options.multiDragKey) {
          this.multiDragKeyDown = false;
        }
      }
    };
    return _extends(MultiDrag, {
      // Static methods & properties
      pluginName: 'multiDrag',
      utils: {
        /**
         * Selects the provided multi-drag item
         * @param  {HTMLElement} el    The element to be selected
         */
        select: function select(el) {
          var sortable = el.parentNode[expando];
          if (!sortable || !sortable.options.multiDrag || ~multiDragElements.indexOf(el)) return;
          if (multiDragSortable && multiDragSortable !== sortable) {
            multiDragSortable.multiDrag._deselectMultiDrag();
            multiDragSortable = sortable;
          }
          toggleClass(el, sortable.options.selectedClass, true);
          multiDragElements.push(el);
        },
        /**
         * Deselects the provided multi-drag item
         * @param  {HTMLElement} el    The element to be deselected
         */
        deselect: function deselect(el) {
          var sortable = el.parentNode[expando],
            index = multiDragElements.indexOf(el);
          if (!sortable || !sortable.options.multiDrag || !~index) return;
          toggleClass(el, sortable.options.selectedClass, false);
          multiDragElements.splice(index, 1);
        }
      },
      eventProperties: function eventProperties() {
        var _this3 = this;
        var oldIndicies = [],
          newIndicies = [];
        multiDragElements.forEach(function (multiDragElement) {
          oldIndicies.push({
            multiDragElement: multiDragElement,
            index: multiDragElement.sortableIndex
          });

          // multiDragElements will already be sorted if folding
          var newIndex;
          if (folding && multiDragElement !== dragEl$1) {
            newIndex = -1;
          } else if (folding) {
            newIndex = index(multiDragElement, ':not(.' + _this3.options.selectedClass + ')');
          } else {
            newIndex = index(multiDragElement);
          }
          newIndicies.push({
            multiDragElement: multiDragElement,
            index: newIndex
          });
        });
        return {
          items: _toConsumableArray(multiDragElements),
          clones: [].concat(multiDragClones),
          oldIndicies: oldIndicies,
          newIndicies: newIndicies
        };
      },
      optionListeners: {
        multiDragKey: function multiDragKey(key) {
          key = key.toLowerCase();
          if (key === 'ctrl') {
            key = 'Control';
          } else if (key.length > 1) {
            key = key.charAt(0).toUpperCase() + key.substr(1);
          }
          return key;
        }
      }
    });
  }
  function insertMultiDragElements(clonesInserted, rootEl) {
    multiDragElements.forEach(function (multiDragElement, i) {
      var target = rootEl.children[multiDragElement.sortableIndex + (clonesInserted ? Number(i) : 0)];
      if (target) {
        rootEl.insertBefore(multiDragElement, target);
      } else {
        rootEl.appendChild(multiDragElement);
      }
    });
  }

  /**
   * Insert multi-drag clones
   * @param  {[Boolean]} elementsInserted  Whether the multi-drag elements are inserted
   * @param  {HTMLElement} rootEl
   */
  function insertMultiDragClones(elementsInserted, rootEl) {
    multiDragClones.forEach(function (clone, i) {
      var target = rootEl.children[clone.sortableIndex + (elementsInserted ? Number(i) : 0)];
      if (target) {
        rootEl.insertBefore(clone, target);
      } else {
        rootEl.appendChild(clone);
      }
    });
  }
  function removeMultiDragElements() {
    multiDragElements.forEach(function (multiDragElement) {
      if (multiDragElement === dragEl$1) return;
      multiDragElement.parentNode && multiDragElement.parentNode.removeChild(multiDragElement);
    });
  }

  Sortable.mount(new AutoScrollPlugin());
  Sortable.mount(Remove, Revert);

  Sortable.mount(new SwapPlugin());
  Sortable.mount(new MultiDragPlugin());

  return Sortable;

})));


================================================
FILE: babel.config.js
================================================
module.exports = function(api) {
	api.cache(true);

	let presets;

	if (process.env.NODE_ENV === 'es') {
		presets = [
			[
				"@babel/preset-env",
				{
					"modules": false
				}
			]
		];
	} else if (process.env.NODE_ENV === 'umd') {
		presets = [
			[
				"@babel/preset-env"
			]
		];
	}

	return {
		plugins: ['@babel/plugin-transform-object-assign'],
		presets
	};
};


================================================
FILE: bower.json
================================================
{
  "name": "Sortable",
  "main": [
    "Sortable.js"
  ],
  "homepage": "http://SortableJS.github.io/Sortable/",
  "authors": [
    "RubaXa <ibnRubaXa@gmail.com>",
    "owenm <owen23355@gmail.com>"
  ],
  "description": "JavaScript library for reorderable drag-and-drop lists on modern browsers and touch devices. No jQuery required. Supports Meteor, AngularJS, React, Polymer, Vue, Knockout and any CSS library, e.g. Bootstrap.",
  "keywords": [
    "sortable",
    "reorder",
    "list",
    "html5",
    "drag",
    "and",
    "drop",
    "dnd",
    "web-components"
  ],
  "license": "MIT",
  "ignore": [
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ]
}


================================================
FILE: entry/entry-complete.js
================================================
import Sortable from './entry-defaults.js';
import Swap from '../plugins/Swap';
import MultiDrag from '../plugins/MultiDrag';

Sortable.mount(new Swap());
Sortable.mount(new MultiDrag());

export default Sortable;


================================================
FILE: entry/entry-core.js
================================================
import Sortable from '../src/Sortable.js';
import AutoScroll from '../plugins/AutoScroll';
import OnSpill from '../plugins/OnSpill';
import Swap from '../plugins/Swap';
import MultiDrag from '../plugins/MultiDrag';

export default Sortable;

export {
	Sortable,

	// Default
	AutoScroll,
	OnSpill,

	// Extra
	Swap,
	MultiDrag
};


================================================
FILE: entry/entry-defaults.js
================================================
import Sortable from '../src/Sortable.js';
import AutoScroll from '../plugins/AutoScroll';
import { RemoveOnSpill, RevertOnSpill } from '../plugins/OnSpill';
// Extra
import Swap from '../plugins/Swap';
import MultiDrag from '../plugins/MultiDrag';

Sortable.mount(new AutoScroll());
Sortable.mount(RemoveOnSpill, RevertOnSpill);

export default Sortable;

export {
	Sortable,

	// Extra
	Swap,
	MultiDrag
};


================================================
FILE: index.html
================================================
<!DOCTYPE html>
<html>
<head>
	<link rel="icon" type="image/png" href="st/og-image.png">
	<title>SortableJS</title>
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
	<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
	<link rel="stylesheet" type="text/css" href="st/theme.css">

	<meta charset="utf-8"/>
	<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
	<meta property="og:image" content="/st/og-image.png"/>
	<meta name="keywords" content="sortable, reorder, list, javascript, html5, drag and drop, dnd, animation, groups, dnd, sortableJS"/>
	<meta name="description" content="Sortable — is a JavaScript library for reorderable drag-and-drop lists on modern browsers and touch devices. No jQuery required. Supports Meteor, AngularJS, React, Polymer, Vue, Knockout and any CSS library, e.g. Bootstrap."/>
	<meta name="viewport" content="width=device-width, initial-scale=0.5"/>
</head>
<body>

	<a href="https://github.com/SortableJS/Sortable"><img style="position: fixed; top: 0; right: 0; border: 0; z-index:99999" src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png" alt="Fork me on GitHub"></a>

	<div class="container">
		<div class="text-center row header">
			<img class="mx-auto d-block" src="st/og-image.png" style="max-width: 200px; max-height: 200px" />
			<h1 class="col-12">SortableJS</h1>
			<h3 class="col-12 text-center">JavaScript library for reorderable drag-and-drop lists</h3>

			<div class="toc col-12 col-md-5 mt-3">
				<h5>Features</h5>
				<li><a href="#simple-list">Simple list</a></li>
				<li><a href="#shared-lists">Shared lists</a></li>
				<li><a href="#cloning">Cloning</a></li>
				<li><a href="#sorting-disabled">Disabling sorting</a></li>
				<li><a href="#handle">Handles</a></li>
				<li><a href="#filter">Filter</a></li>
				<li><a href="#thresholds">Thresholds</a></li>
				<h5>Examples</h5>
				<li><a href="#grid">Grid</a></li>
				<li><a href="#nested">Nested sortables</a></li>
				<h5>Plugins</h5>
				<li><a href="#multi-drag">MultiDrag</a></li>
				<li><a href="#swap">Swap</a></li>
				<h5><a href="#comparisons">Comparisons</a></h5>
				<h5><a href="#frameworks">Framework Support</a></h5>
			</div>
		</div>

		<div class="row">
			<h2 class="col-12">Features</h2>
		</div>
		<hr />
		<div id="simple-list" class="row">
			<h4 class="col-12">Simple list example</h4>
			<div id="example1" class="list-group col">
				<div class="list-group-item">Item 1</div>
				<div class="list-group-item">Item 2</div>
				<div class="list-group-item">Item 3</div>
				<div class="list-group-item">Item 4</div>
				<div class="list-group-item">Item 5</div>
				<div class="list-group-item">Item 6</div>
			</div>
			<div style="padding: 0" class="col-12">
<pre class="prettyprint">new Sortable(example1, {
    animation: 150,
    ghostClass: 'blue-background-class'
});</pre>
			</div>
		</div>
		<hr />

		<div id="shared-lists" class="row">
			<h4 class="col-12">Shared lists</h4>
			<div id="example2-left" class="list-group col">
				<div class="list-group-item">Item 1</div>
				<div class="list-group-item">Item 2</div>
				<div class="list-group-item">Item 3</div>
				<div class="list-group-item">Item 4</div>
				<div class="list-group-item">Item 5</div>
				<div class="list-group-item">Item 6</div>
			</div>

			<div id="example2-right" class="list-group col">
				<div class="list-group-item tinted">Item 1</div>
				<div class="list-group-item tinted">Item 2</div>
				<div class="list-group-item tinted">Item 3</div>
				<div class="list-group-item tinted">Item 4</div>
				<div class="list-group-item tinted">Item 5</div>
				<div class="list-group-item tinted">Item 6</div>
			</div>
			<div style="padding: 0" class="col-12">
<pre class="prettyprint">new Sortable(example2Left, {
    group: 'shared', // set both lists to same group
    animation: 150
});

new Sortable(example2Right, {
    group: 'shared',
    animation: 150
});</pre>
			</div>
		</div>
		<hr />

		<div id="cloning" class="row">
			<h4 class="col-12">Cloning</h4>
			<p class="col-12">Try dragging from one list to another. The item you drag will be cloned and the clone will stay in the original list.</p>
			<div id="example3-left" class="list-group col">
				<div class="list-group-item">Item 1</div>
				<div class="list-group-item">Item 2</div>
				<div class="list-group-item">Item 3</div>
				<div class="list-group-item">Item 4</div>
				<div class="list-group-item">Item 5</div>
				<div class="list-group-item">Item 6</div>
			</div>

			<div id="example3-right" class="list-group col">
				<div class="list-group-item tinted">Item 1</div>
				<div class="list-group-item tinted">Item 2</div>
				<div class="list-group-item tinted">Item 3</div>
				<div class="list-group-item tinted">Item 4</div>
				<div class="list-group-item tinted">Item 5</div>
				<div class="list-group-item tinted">Item 6</div>
			</div>
			<div style="padding: 0" class="col-12">
<pre class="prettyprint">new Sortable(example3Left, {
    group: {
        name: 'shared',
        pull: 'clone' // To clone: set pull to 'clone'
    },
    animation: 150
});

new Sortable(example3Right, {
    group: {
        name: 'shared',
        pull: 'clone'
    },
    animation: 150
});</pre>
			</div>
		</div>
		<hr />

		<div id="sorting-disabled" class="row">
			<h4 class="col-12">Disabling Sorting</h4>
			<p class="col-12">Try sorting the list on the left. It is not possible because it has it's <code>sort</code> option set to false. However, you can still drag from the list on the left to the list on the right.</p>
			<div id="example4-left" class="list-group col">
				<div class="list-group-item">Item 1</div>
				<div class="list-group-item">Item 2</div>
				<div class="list-group-item">Item 3</div>
				<div class="list-group-item">Item 4</div>
				<div class="list-group-item">Item 5</div>
				<div class="list-group-item">Item 6</div>
			</div>

			<div id="example4-right" class="list-group col">
				<div class="list-group-item tinted">Item 1</div>
				<div class="list-group-item tinted">Item 2</div>
				<div class="list-group-item tinted">Item 3</div>
				<div class="list-group-item tinted">Item 4</div>
				<div class="list-group-item tinted">Item 5</div>
				<div class="list-group-item tinted">Item 6</div>
			</div>
			<div style="padding: 0" class="col-12">
<pre class="prettyprint">new Sortable(example4Left, {
    group: {
        name: 'shared',
        pull: 'clone',
        put: false // Do not allow items to be put into this list
    },
    animation: 150,
    sort: false // To disable sorting: set sort to false
});

new Sortable(example4Right, {
    group: 'shared',
    animation: 150
});</pre>
			</div>
		</div>
		<hr />

		<div id="handle" class="row">
			<h4 class="col-12">Handle</h4>
			<div id="example5" class="list-group col">
				<div class="list-group-item"><i class="fas fa-arrows-alt handle"></i>&nbsp;&nbsp;Item 1</div>
				<div class="list-group-item"><i class="fas fa-arrows-alt handle"></i>&nbsp;&nbsp;Item 2</div>
				<div class="list-group-item"><i class="fas fa-arrows-alt handle"></i>&nbsp;&nbsp;Item 3</div>
				<div class="list-group-item"><i class="fas fa-arrows-alt handle"></i>&nbsp;&nbsp;Item 4</div>
				<div class="list-group-item"><i class="fas fa-arrows-alt handle"></i>&nbsp;&nbsp;Item 5</div>
				<div class="list-group-item"><i class="fas fa-arrows-alt handle"></i>&nbsp;&nbsp;Item 6</div>
			</div>
			<div style="padding: 0" class="col-12">
<pre class="prettyprint">new Sortable(example5, {
    handle: '.handle', // handle's class
    animation: 150
});</pre>
			</div>
		</div>
		<hr />

		<div id="filter" class="row">
			<h4 class="col-12">Filter</h4>
			<p class="col-12">Try dragging the item with a red background. It cannot be done, because that item is filtered out using the <code>filter</code> option.</p>
			<div id="example6" class="list-group col">
				<div class="list-group-item">Item 1</div>
				<div class="list-group-item">Item 2</div>
				<div class="list-group-item">Item 3</div>
				<div class="list-group-item bg-danger filtered">Filtered</div>
				<div class="list-group-item">Item 4</div>
				<div class="list-group-item">Item 5</div>
			</div>
			<div style="padding: 0" class="col-12">
<pre class="prettyprint">new Sortable(example6, {
    filter: '.filtered', // 'filtered' class is not draggable
    animation: 150
});</pre>
			</div>
		</div>
		<hr />

		<div id="thresholds" class="row">
			<h4 class="col-12">Thresholds</h4>
			<p class="col-12">Try modifying the inputs below to affect the swap thresholds. You can see the swap zones of the squares colored in dark blue, while the "dead zones" (that do not cause a swap) are colored in light blue.</p>
			<div id="example7" class="square-section col">
				<div class="square">
					<div style="display: none;" class="inverted-swap-threshold-indicator indicator-left"></div>
					<div class="swap-threshold-indicator"></div>
					<div style="display: none;" class="inverted-swap-threshold-indicator indicator-right"></div>
					<div class="num-indicator">1</div>
				</div><!--
			 --><div class="square">
					<div style="display: none;" class="inverted-swap-threshold-indicator indicator-left"></div>
					<div class="swap-threshold-indicator"></div>
					<div style="display: none;" class="inverted-swap-threshold-indicator indicator-right"></div>
					<div class="num-indicator">2</div>
				</div>
			</div>
			<div class="col-12 input-section">
				<form>
					<div class="form-group row">
						<label class="col-sm-2 col-form-label" for="example7SwapThresholdInput">Swap Threshold</label>
						<div class="col-sm-8 col-form-label">
							<input min="0" max="1" value="1" step="0.01" type="range" class="form-control-range" id="example7SwapThresholdInput">
						</div>
					</div>
					<div class="form-group row">
						<div class="col-sm-2">Invert Swap</div>
						<div class="col-sm-10">
							<div class="form-check">
								<input class="form-check-input" type="checkbox" id="example7InvertSwapInput">
							</div>
						</div>
					</div>
					<div class="form-group row">
						<label class="col-sm-2 col-form-label" for="example7DirectionInput">Direction</label>
						<select class="col-sm-4 form-control" id="example7DirectionInput">
							<option value="h" selected>Horizontal</option>
							<option value="v">Vertical</option>
						</select>
					</div>
				</form>
			</div>
			<div style="padding: 0" class="col-12">
<pre class="prettyprint">new Sortable(example7, {
    swapThreshold: <span id="example7SwapThresholdCode">1</span>,<span id="example7InvertSwapCode" style="display: none">
    invertSwap: true,</span>
    animation: 150
});</pre>
			</div>
		</div>


		<div class="row">
			<h2 class="col-12">Examples</h2>
		</div>
		<hr />

		<div id="grid" class="row">
			<h4 class="col-12">Grid Example</h4>
			<div id="gridDemo" class="col">
				<div class="grid-square">Item 1</div><!--
			 --><div class="grid-square">Item 2</div><!--
			 --><div class="grid-square">Item 3</div><!--
			 --><div class="grid-square">Item 4</div><!--
			 --><div class="grid-square">Item 5</div><!--
			 --><div class="grid-square">Item 6</div><!--
			 --><div class="grid-square">Item 7</div><!--
			 --><div class="grid-square">Item 8</div><!--
			 --><div class="grid-square">Item 9</div><!--
			 --><div class="grid-square">Item 10</div><!--
			 --><div class="grid-square">Item 11</div><!--
			 --><div class="grid-square">Item 12</div><!--
			 --><div class="grid-square">Item 13</div><!--
			 --><div class="grid-square">Item 14</div><!--
			 --><div class="grid-square">Item 15</div><!--
			 --><div class="grid-square">Item 16</div><!--
			 --><div class="grid-square">Item 17</div><!--
			 --><div class="grid-square">Item 18</div><!--
			 --><div class="grid-square">Item 19</div><!--
			 --><div class="grid-square">Item 20</div>
			</div>
		</div>
		<hr />

		<div id="nested" class="row">
			<h4 class="col-12">Nested Sortables Example</h4>
			<p class="col-12">NOTE: When using nested Sortables with animation, it is recommended that the <code>fallbackOnBody</code> option is set to true. <br />It is also always recommended that either the <code>invertSwap</code> option is set to true, or the <code>swapThreshold</code> option is lower than the default value of 1 (eg <code>0.65</code>).</p>
			<div id="nestedDemo" class="list-group col nested-sortable">
				<div class="list-group-item nested-1">Item 1.1
					<div class="list-group nested-sortable">
						<div class="list-group-item nested-2">Item 2.1</div>
						<div class="list-group-item nested-2">Item 2.2
							<div class="list-group nested-sortable">
								<div class="list-group-item nested-3">Item 3.1</div>
								<div class="list-group-item nested-3">Item 3.2</div>
								<div class="list-group-item nested-3">Item 3.3</div>
								<div class="list-group-item nested-3">Item 3.4</div>
							</div>
						</div>
						<div class="list-group-item nested-2">Item 2.3</div>
						<div class="list-group-item nested-2">Item 2.4</div>
					</div>
				</div>
				<div class="list-group-item nested-1">Item 1.2</div>
				<div class="list-group-item nested-1">Item 1.3</div>
				<div class="list-group-item nested-1">Item 1.4
					<div class="list-group nested-sortable">
						<div class="list-group-item nested-2">Item 2.1</div>
						<div class="list-group-item nested-2">Item 2.2</div>
						<div class="list-group-item nested-2">Item 2.3</div>
						<div class="list-group-item nested-2">Item 2.4</div>
					</div>
				</div>
				<div class="list-group-item nested-1">Item 1.5</div>
			</div>
			<div style="padding: 0" class="col-12">
<pre class="prettyprint">// Loop through each nested sortable element
for (var i = 0; i < nestedSortables.length; i++) {
	new Sortable(nestedSortables[i], {
		group: 'nested',
		animation: 150,
		fallbackOnBody: true,
		swapThreshold: 0.65
	});
}</pre>
			</div>
		</div>

		<div class="row">
			<h2 class="col-12">Plugins</h2>
		</div>
		<hr />

		<div id="multi-drag" class="row">
			<h4 class="col-12">MultiDrag</h4>
			<p class="col-12">The <a target="_blank" href="https://github.com/SortableJS/Sortable/tree/master/plugins/MultiDrag">MultiDrag</a> plugin allows for multiple items to be dragged at a time. You can click to "select" multiple items, and then drag them as one item.</p>
			<div id="multiDragDemo" class="list-group col">
				<div class="list-group-item">Item 1</div>
				<div class="list-group-item">Item 2</div>
				<div class="list-group-item">Item 3</div>
				<div class="list-group-item">Item 4</div>
				<div class="list-group-item">Item 5</div>
				<div class="list-group-item">Item 6</div>
			</div>
			<div style="padding: 0" class="col-12">
<pre class="prettyprint">new Sortable(multiDragDemo, {
	multiDrag: true,
	selectedClass: 'selected',
	fallbackTolerance: 3, // So that we can select items on mobile
	animation: 150
});</pre>
			</div>
		</div>
		<hr />

		<div id="swap" class="row">
			<h4 class="col-12">Swap</h4>
			<p class="col-12">The <a target="_blank" href="https://github.com/SortableJS/Sortable/tree/master/plugins/Swap">Swap</a> plugin changes the behaviour of Sortable to allow for items to be swapped with eachother rather than sorted.</p>
			<div id="swapDemo" class="list-group col">
				<div class="list-group-item">Item 1</div>
				<div class="list-group-item">Item 2</div>
				<div class="list-group-item">Item 3</div>
				<div class="list-group-item">Item 4</div>
				<div class="list-group-item">Item 5</div>
				<div class="list-group-item">Item 6</div>
			</div>
			<div style="padding: 0" class="col-12">
<pre class="prettyprint">new Sortable(swapDemo, {
	swap: true, // Enable swap plugin
	swapClass: 'highlight', // The class applied to the hovered swap item
	animation: 150
});</pre>
			</div>
		</div>
		<hr />



		<div class="mt-4"></div>

		<div id="comparisons" class="row">
			<h2 class="col-12">Comparisons</h2>
		</div>
		<hr />


		<div class="row frameworks">
			<h2 class="col-12 text-center">jQuery-UI</h2>
			<iframe class="mx-auto" src="https://player.vimeo.com/video/311581236?title=0&byline=0&portrait=0" width="640" height="361" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>

			<h2 class="col-12 text-center mt-5">Dragula</h2>
			<iframe class="mx-auto" src="https://player.vimeo.com/video/311584137?title=0&byline=0&portrait=0" width="640" height="361" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
		</div>

		<div class="mt-4"></div>

		<div id="frameworks" class="row">
			<h2 class="col-12">Framework Support</h2>
		</div>
		<hr />

		<div class="row frameworks">

			<h3 class="col-6">Vue</h3>
			<h3 class="col-6"><a target="_blank" href="https://github.com/SortableJS/Vue.Draggable">Vue.Draggable</a></h3>

			<h3 class="col-6">React</h3>
			<h3 class="col-6"><a target="_blank" href="https://github.com/SortableJS/react-sortablejs">react-sortablejs</a></h3>

			<h3 class="col-6">Angular</h3>
			<h3 class="col-6"><a target="_blank" href="https://github.com/SortableJS/ngx-sortablejs">ngx-sortablejs</a></h3>

			<h3 class="col-6">jQuery</h3>
			<h3 class="col-6"><a target="_blank" href="https://github.com/SortableJS/jquery-sortablejs">jquery-sortablejs</a></h3>

			<h3 class="col-6">Knockout</h3>
			<h3 class="col-6"><a target="_blank" href="https://github.com/SortableJS/knockout-sortablejs">knockout-sortablejs</a></h3>

			<h3 class="col-6">Meteor</h3>
			<h3 class="col-6"><a target="_blank" href="https://github.com/SortableJS/meteor-sortablejs">meteor-sortablejs</a></h3>

			<h3 class="col-6">Polymer</h3>
			<h3 class="col-6"><a target="_blank" href="https://github.com/SortableJS/polymer-sortablejs">polymer-sortablejs</a></h3>

			<h3 class="col-6">Ember</h3>
			<h3 class="col-6"><a target="_blank" href="https://github.com/SortableJS/ember-sortablejs">ember-sortablejs</a></h3>
		</div>

	</div>


	<!-- Latest Sortable -->
	<script src="./Sortable.js"></script>

	<script type="text/javascript" src="st/prettify/prettify.js"></script>
	<script type="text/javascript" src="st/prettify/run_prettify.js"></script>

	<script src="st/app.js"></script>
</body>
</html>


================================================
FILE: modular/sortable.complete.esm.js
================================================
/**!
 * Sortable 1.15.7
 * @author	RubaXa   <trash@rubaxa.org>
 * @author	owenm    <owen23355@gmail.com>
 * @license MIT
 */
function _arrayLikeToArray(r, a) {
  (null == a || a > r.length) && (a = r.length);
  for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
  return n;
}
function _arrayWithoutHoles(r) {
  if (Array.isArray(r)) return _arrayLikeToArray(r);
}
function _defineProperty(e, r, t) {
  return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
    value: t,
    enumerable: !0,
    configurable: !0,
    writable: !0
  }) : e[r] = t, e;
}
function _extends() {
  return _extends = Object.assign ? Object.assign.bind() : function (n) {
    for (var e = 1; e < arguments.length; e++) {
      var t = arguments[e];
      for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
    }
    return n;
  }, _extends.apply(null, arguments);
}
function _iterableToArray(r) {
  if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r);
}
function _nonIterableSpread() {
  throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function ownKeys(e, r) {
  var t = Object.keys(e);
  if (Object.getOwnPropertySymbols) {
    var o = Object.getOwnPropertySymbols(e);
    r && (o = o.filter(function (r) {
      return Object.getOwnPropertyDescriptor(e, r).enumerable;
    })), t.push.apply(t, o);
  }
  return t;
}
function _objectSpread2(e) {
  for (var r = 1; r < arguments.length; r++) {
    var t = null != arguments[r] ? arguments[r] : {};
    r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {
      _defineProperty(e, r, t[r]);
    }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
      Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
    });
  }
  return e;
}
function _objectWithoutProperties(e, t) {
  if (null == e) return {};
  var o,
    r,
    i = _objectWithoutPropertiesLoose(e, t);
  if (Object.getOwnPropertySymbols) {
    var n = Object.getOwnPropertySymbols(e);
    for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]);
  }
  return i;
}
function _objectWithoutPropertiesLoose(r, e) {
  if (null == r) return {};
  var t = {};
  for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
    if (-1 !== e.indexOf(n)) continue;
    t[n] = r[n];
  }
  return t;
}
function _toConsumableArray(r) {
  return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();
}
function _toPrimitive(t, r) {
  if ("object" != typeof t || !t) return t;
  var e = t[Symbol.toPrimitive];
  if (void 0 !== e) {
    var i = e.call(t, r || "default");
    if ("object" != typeof i) return i;
    throw new TypeError("@@toPrimitive must return a primitive value.");
  }
  return ("string" === r ? String : Number)(t);
}
function _toPropertyKey(t) {
  var i = _toPrimitive(t, "string");
  return "symbol" == typeof i ? i : i + "";
}
function _typeof(o) {
  "@babel/helpers - typeof";

  return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
    return typeof o;
  } : function (o) {
    return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
  }, _typeof(o);
}
function _unsupportedIterableToArray(r, a) {
  if (r) {
    if ("string" == typeof r) return _arrayLikeToArray(r, a);
    var t = {}.toString.call(r).slice(8, -1);
    return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
  }
}

var version = "1.15.7";

function userAgent(pattern) {
  if (typeof window !== 'undefined' && window.navigator) {
    return !! /*@__PURE__*/navigator.userAgent.match(pattern);
  }
}
var IE11OrLess = userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i);
var Edge = userAgent(/Edge/i);
var FireFox = userAgent(/firefox/i);
var Safari = userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i);
var IOS = userAgent(/iP(ad|od|hone)/i);
var ChromeForAndroid = userAgent(/chrome/i) && userAgent(/android/i);

var captureMode = {
  capture: false,
  passive: false
};
function on(el, event, fn) {
  el.addEventListener(event, fn, !IE11OrLess && captureMode);
}
function off(el, event, fn) {
  el.removeEventListener(event, fn, !IE11OrLess && captureMode);
}
function matches( /**HTMLElement*/el, /**String*/selector) {
  if (!selector) return;
  selector[0] === '>' && (selector = selector.substring(1));
  if (el) {
    try {
      if (el.matches) {
        return el.matches(selector);
      } else if (el.msMatchesSelector) {
        return el.msMatchesSelector(selector);
      } else if (el.webkitMatchesSelector) {
        return el.webkitMatchesSelector(selector);
      }
    } catch (_) {
      return false;
    }
  }
  return false;
}
function getParentOrHost(el) {
  return el.host && el !== document && el.host.nodeType && el.host !== el ? el.host : el.parentNode;
}
function closest( /**HTMLElement*/el, /**String*/selector, /**HTMLElement*/ctx, includeCTX) {
  if (el) {
    ctx = ctx || document;
    do {
      if (selector != null && (selector[0] === '>' ? el.parentNode === ctx && matches(el, selector) : matches(el, selector)) || includeCTX && el === ctx) {
        return el;
      }
      if (el === ctx) break;
      /* jshint boss:true */
    } while (el = getParentOrHost(el));
  }
  return null;
}
var R_SPACE = /\s+/g;
function toggleClass(el, name, state) {
  if (el && name) {
    if (el.classList) {
      el.classList[state ? 'add' : 'remove'](name);
    } else {
      var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' ');
      el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' ');
    }
  }
}
function css(el, prop, val) {
  var style = el && el.style;
  if (style) {
    if (val === void 0) {
      if (document.defaultView && document.defaultView.getComputedStyle) {
        val = document.defaultView.getComputedStyle(el, '');
      } else if (el.currentStyle) {
        val = el.currentStyle;
      }
      return prop === void 0 ? val : val[prop];
    } else {
      if (!(prop in style) && prop.indexOf('webkit') === -1) {
        prop = '-webkit-' + prop;
      }
      style[prop] = val + (typeof val === 'string' ? '' : 'px');
    }
  }
}
function matrix(el, selfOnly) {
  var appliedTransforms = '';
  if (typeof el === 'string') {
    appliedTransforms = el;
  } else {
    do {
      var transform = css(el, 'transform');
      if (transform && transform !== 'none') {
        appliedTransforms = transform + ' ' + appliedTransforms;
      }
      /* jshint boss:true */
    } while (!selfOnly && (el = el.parentNode));
  }
  var matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix || window.MSCSSMatrix;
  /*jshint -W056 */
  return matrixFn && new matrixFn(appliedTransforms);
}
function find(ctx, tagName, iterator) {
  if (ctx) {
    var list = ctx.getElementsByTagName(tagName),
      i = 0,
      n = list.length;
    if (iterator) {
      for (; i < n; i++) {
        iterator(list[i], i);
      }
    }
    return list;
  }
  return [];
}
function getWindowScrollingElement() {
  var scrollingElement = document.scrollingElement;
  if (scrollingElement) {
    return scrollingElement;
  } else {
    return document.documentElement;
  }
}

/**
 * Returns the "bounding client rect" of given element
 * @param  {HTMLElement} el                       The element whose boundingClientRect is wanted
 * @param  {[Boolean]} relativeToContainingBlock  Whether the rect should be relative to the containing block of (including) the container
 * @param  {[Boolean]} relativeToNonStaticParent  Whether the rect should be relative to the relative parent of (including) the contaienr
 * @param  {[Boolean]} undoScale                  Whether the container's scale() should be undone
 * @param  {[HTMLElement]} container              The parent the element will be placed in
 * @return {Object}                               The boundingClientRect of el, with specified adjustments
 */
function getRect(el, relativeToContainingBlock, relativeToNonStaticParent, undoScale, container) {
  if (!el.getBoundingClientRect && el !== window) return;
  var elRect, top, left, bottom, right, height, width;
  if (el !== window && el.parentNode && el !== getWindowScrollingElement()) {
    elRect = el.getBoundingClientRect();
    top = elRect.top;
    left = elRect.left;
    bottom = elRect.bottom;
    right = elRect.right;
    height = elRect.height;
    width = elRect.width;
  } else {
    top = 0;
    left = 0;
    bottom = window.innerHeight;
    right = window.innerWidth;
    height = window.innerHeight;
    width = window.innerWidth;
  }
  if ((relativeToContainingBlock || relativeToNonStaticParent) && el !== window) {
    // Adjust for translate()
    container = container || el.parentNode;

    // solves #1123 (see: https://stackoverflow.com/a/37953806/6088312)
    // Not needed on <= IE11
    if (!IE11OrLess) {
      do {
        if (container && container.getBoundingClientRect && (css(container, 'transform') !== 'none' || relativeToNonStaticParent && css(container, 'position') !== 'static')) {
          var containerRect = container.getBoundingClientRect();

          // Set relative to edges of padding box of container
          top -= containerRect.top + parseInt(css(container, 'border-top-width'));
          left -= containerRect.left + parseInt(css(container, 'border-left-width'));
          bottom = top + elRect.height;
          right = left + elRect.width;
          break;
        }
        /* jshint boss:true */
      } while (container = container.parentNode);
    }
  }
  if (undoScale && el !== window) {
    // Adjust for scale()
    var elMatrix = matrix(container || el),
      scaleX = elMatrix && elMatrix.a,
      scaleY = elMatrix && elMatrix.d;
    if (elMatrix) {
      top /= scaleY;
      left /= scaleX;
      width /= scaleX;
      height /= scaleY;
      bottom = top + height;
      right = left + width;
    }
  }
  return {
    top: top,
    left: left,
    bottom: bottom,
    right: right,
    width: width,
    height: height
  };
}

/**
 * Checks if a side of an element is scrolled past a side of its parents
 * @param  {HTMLElement}  el           The element who's side being scrolled out of view is in question
 * @param  {String}       elSide       Side of the element in question ('top', 'left', 'right', 'bottom')
 * @param  {String}       parentSide   Side of the parent in question ('top', 'left', 'right', 'bottom')
 * @return {HTMLElement}               The parent scroll element that the el's side is scrolled past, or null if there is no such element
 */
function isScrolledPast(el, elSide, parentSide) {
  var parent = getParentAutoScrollElement(el, true),
    elSideVal = getRect(el)[elSide];

  /* jshint boss:true */
  while (parent) {
    var parentSideVal = getRect(parent)[parentSide],
      visible = void 0;
    if (parentSide === 'top' || parentSide === 'left') {
      visible = elSideVal >= parentSideVal;
    } else {
      visible = elSideVal <= parentSideVal;
    }
    if (!visible) return parent;
    if (parent === getWindowScrollingElement()) break;
    parent = getParentAutoScrollElement(parent, false);
  }
  return false;
}

/**
 * Gets nth child of el, ignoring hidden children, sortable's elements (does not ignore clone if it's visible)
 * and non-draggable elements
 * @param  {HTMLElement} el       The parent element
 * @param  {Number} childNum      The index of the child
 * @param  {Object} options       Parent Sortable's options
 * @return {HTMLElement}          The child at index childNum, or null if not found
 */
function getChild(el, childNum, options, includeDragEl) {
  var currentChild = 0,
    i = 0,
    children = el.children;
  while (i < children.length) {
    if (children[i].style.display !== 'none' && children[i] !== Sortable.ghost && (includeDragEl || children[i] !== Sortable.dragged) && closest(children[i], options.draggable, el, false)) {
      if (currentChild === childNum) {
        return children[i];
      }
      currentChild++;
    }
    i++;
  }
  return null;
}

/**
 * Gets the last child in the el, ignoring ghostEl or invisible elements (clones)
 * @param  {HTMLElement} el       Parent element
 * @param  {selector} selector    Any other elements that should be ignored
 * @return {HTMLElement}          The last child, ignoring ghostEl
 */
function lastChild(el, selector) {
  var last = el.lastElementChild;
  while (last && (last === Sortable.ghost || css(last, 'display') === 'none' || selector && !matches(last, selector))) {
    last = last.previousElementSibling;
  }
  return last || null;
}

/**
 * Returns the index of an element within its parent for a selected set of
 * elements
 * @param  {HTMLElement} el
 * @param  {selector} selector
 * @return {number}
 */
function index(el, selector) {
  var index = 0;
  if (!el || !el.parentNode) {
    return -1;
  }

  /* jshint boss:true */
  while (el = el.previousElementSibling) {
    if (el.nodeName.toUpperCase() !== 'TEMPLATE' && el !== Sortable.clone && (!selector || matches(el, selector))) {
      index++;
    }
  }
  return index;
}

/**
 * Returns the scroll offset of the given element, added with all the scroll offsets of parent elements.
 * The value is returned in real pixels.
 * @param  {HTMLElement} el
 * @return {Array}             Offsets in the format of [left, top]
 */
function getRelativeScrollOffset(el) {
  var offsetLeft = 0,
    offsetTop = 0,
    winScroller = getWindowScrollingElement();
  if (el) {
    do {
      var elMatrix = matrix(el),
        scaleX = elMatrix.a,
        scaleY = elMatrix.d;
      offsetLeft += el.scrollLeft * scaleX;
      offsetTop += el.scrollTop * scaleY;
    } while (el !== winScroller && (el = el.parentNode));
  }
  return [offsetLeft, offsetTop];
}

/**
 * Returns the index of the object within the given array
 * @param  {Array} arr   Array that may or may not hold the object
 * @param  {Object} obj  An object that has a key-value pair unique to and identical to a key-value pair in the object you want to find
 * @return {Number}      The index of the object in the array, or -1
 */
function indexOfObject(arr, obj) {
  for (var i in arr) {
    if (!arr.hasOwnProperty(i)) continue;
    for (var key in obj) {
      if (obj.hasOwnProperty(key) && obj[key] === arr[i][key]) return Number(i);
    }
  }
  return -1;
}
function getParentAutoScrollElement(el, includeSelf) {
  // skip to window
  if (!el || !el.getBoundingClientRect) return getWindowScrollingElement();
  var elem = el;
  var gotSelf = false;
  do {
    // we don't need to get elem css if it isn't even overflowing in the first place (performance)
    if (elem.clientWidth < elem.scrollWidth || elem.clientHeight < elem.scrollHeight) {
      var elemCSS = css(elem);
      if (elem.clientWidth < elem.scrollWidth && (elemCSS.overflowX == 'auto' || elemCSS.overflowX == 'scroll') || elem.clientHeight < elem.scrollHeight && (elemCSS.overflowY == 'auto' || elemCSS.overflowY == 'scroll')) {
        if (!elem.getBoundingClien
Download .txt
gitextract_s2mraq4s/

├── .circleci/
│   └── config.yml
├── .editorconfig
├── .github/
│   └── ISSUE_TEMPLATE/
│       ├── bug-report.md
│       ├── custom-template.md
│       └── feature-request.md
├── .gitignore
├── .jshintrc
├── .testcaferc.json
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── Sortable.js
├── babel.config.js
├── bower.json
├── entry/
│   ├── entry-complete.js
│   ├── entry-core.js
│   └── entry-defaults.js
├── index.html
├── modular/
│   ├── sortable.complete.esm.js
│   ├── sortable.core.esm.js
│   └── sortable.esm.js
├── package.json
├── plugins/
│   ├── AutoScroll/
│   │   ├── AutoScroll.js
│   │   ├── README.md
│   │   └── index.js
│   ├── MultiDrag/
│   │   ├── MultiDrag.js
│   │   ├── README.md
│   │   └── index.js
│   ├── OnSpill/
│   │   ├── OnSpill.js
│   │   ├── README.md
│   │   └── index.js
│   ├── README.md
│   └── Swap/
│       ├── README.md
│       ├── Swap.js
│       └── index.js
├── scripts/
│   ├── banner.js
│   ├── build.js
│   ├── esm-build.js
│   ├── minify.js
│   ├── test-compat.js
│   ├── test.js
│   └── umd-build.js
├── src/
│   ├── Animation.js
│   ├── BrowserInfo.js
│   ├── EventDispatcher.js
│   ├── PluginManager.js
│   ├── Sortable.js
│   └── utils.js
├── st/
│   ├── app.js
│   ├── iframe/
│   │   ├── frame.html
│   │   └── index.html
│   ├── prettify/
│   │   ├── prettify.css
│   │   ├── prettify.js
│   │   └── run_prettify.js
│   └── theme.css
└── tests/
    ├── Sortable.compat.test.js
    ├── Sortable.test.js
    ├── dual-list.html
    ├── empty-list.html
    ├── filter.html
    ├── handles.html
    ├── nested.html
    ├── single-list.html
    └── style.css
Download .txt
SYMBOL INDEX (411 symbols across 17 files)

FILE: Sortable.js
  function _arrayLikeToArray (line 13) | function _arrayLikeToArray(r, a) {
  function _arrayWithoutHoles (line 18) | function _arrayWithoutHoles(r) {
  function _defineProperty (line 21) | function _defineProperty(e, r, t) {
  function _extends (line 29) | function _extends() {
  function _iterableToArray (line 38) | function _iterableToArray(r) {
  function _nonIterableSpread (line 41) | function _nonIterableSpread() {
  function ownKeys (line 44) | function ownKeys(e, r) {
  function _objectSpread2 (line 54) | function _objectSpread2(e) {
  function _objectWithoutProperties (line 65) | function _objectWithoutProperties(e, t) {
  function _objectWithoutPropertiesLoose (line 76) | function _objectWithoutPropertiesLoose(r, e) {
  function _toConsumableArray (line 85) | function _toConsumableArray(r) {
  function _toPrimitive (line 88) | function _toPrimitive(t, r) {
  function _toPropertyKey (line 98) | function _toPropertyKey(t) {
  function _typeof (line 102) | function _typeof(o) {
  function _unsupportedIterableToArray (line 111) | function _unsupportedIterableToArray(r, a) {
  function userAgent (line 121) | function userAgent(pattern) {
  function on (line 137) | function on(el, event, fn) {
  function off (line 140) | function off(el, event, fn) {
  function matches (line 143) | function matches( /**HTMLElement*/el, /**String*/selector) {
  function getParentOrHost (line 161) | function getParentOrHost(el) {
  function closest (line 164) | function closest( /**HTMLElement*/el, /**String*/selector, /**HTMLElemen...
  function toggleClass (line 178) | function toggleClass(el, name, state) {
  function css (line 188) | function css(el, prop, val) {
  function matrix (line 206) | function matrix(el, selfOnly) {
  function find (line 223) | function find(ctx, tagName, iterator) {
  function getWindowScrollingElement (line 237) | function getWindowScrollingElement() {
  function getRect (line 255) | function getRect(el, relativeToContainingBlock, relativeToNonStaticParen...
  function isScrolledPast (line 327) | function isScrolledPast(el, elSide, parentSide) {
  function getChild (line 355) | function getChild(el, childNum, options, includeDragEl) {
  function lastChild (line 377) | function lastChild(el, selector) {
  function index (line 392) | function index(el, selector) {
  function getRelativeScrollOffset (line 413) | function getRelativeScrollOffset(el) {
  function indexOfObject (line 435) | function indexOfObject(arr, obj) {
  function getParentAutoScrollElement (line 444) | function getParentAutoScrollElement(el, includeSelf) {
  function extend (line 463) | function extend(dst, src) {
  function isRectEqual (line 473) | function isRectEqual(rect1, rect2) {
  function throttle (line 477) | function throttle(callback, ms) {
  function cancelThrottle (line 493) | function cancelThrottle() {
  function scrollBy (line 497) | function scrollBy(el, x, y) {
  function clone (line 501) | function clone(el) {
  function setRect (line 512) | function setRect(el, rect) {
  function unsetRect (line 519) | function unsetRect(el) {
  function getChildContainingRectFromElement (line 526) | function getChildContainingRectFromElement(container, options, ghostEl) {
  function AnimationStateManager (line 545) | function AnimationStateManager() {
  function repaint (line 675) | function repaint(target) {
  function calculateRealTime (line 678) | function calculateRealTime(animatingRect, fromRect, toRect, options) {
  function dispatchEvent (line 769) | function dispatchEvent(_ref) {
  function _dispatchEvent (line 860) | function _dispatchEvent(info) {
  function toFn (line 976) | function toFn(value, pull) {
  function Sortable (line 1061) | function Sortable(el, options) {
  function dragOverEvent (line 1644) | function dragOverEvent(name, extra) {
  function capture (line 1664) | function capture() {
  function completed (line 1673) | function completed(insertion) {
  function changed (line 1726) | function changed() {
  function _globalDragOver (line 2210) | function _globalDragOver( /**Event*/evt) {
  function _onMove (line 2216) | function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, o...
  function _disableDraggable (line 2245) | function _disableDraggable(el) {
  function _unsilent (line 2248) | function _unsilent() {
  function _ghostIsFirst (line 2251) | function _ghostIsFirst(evt, vertical, sortable) {
  function _ghostIsLast (line 2257) | function _ghostIsLast(evt, vertical, sortable) {
  function _getSwapDirection (line 2263) | function _getSwapDirection(evt, target, targetRect, vertical, swapThresh...
  function _getInsertDirection (line 2310) | function _getInsertDirection(target) {
  function _generateId (line 2324) | function _generateId(el) {
  function _saveInputCheckedState (line 2333) | function _saveInputCheckedState(root) {
  function _nextTick (line 2342) | function _nextTick(fn) {
  function _cancelNextTick (line 2345) | function _cancelNextTick(id) {
  function AutoScrollPlugin (line 2427) | function AutoScrollPlugin() {
  function clearAutoScrolls (line 2530) | function clearAutoScrolls() {
  function clearPointerElemChangedInterval (line 2536) | function clearPointerElemChangedInterval() {
  function Revert (line 2647) | function Revert() {}
  function Remove (line 2677) | function Remove() {}
  function SwapPlugin (line 2694) | function SwapPlugin() {
  function swapNodes (line 2761) | function swapNodes(n1, n2) {
  function MultiDragPlugin (line 2789) | function MultiDragPlugin() {
  function insertMultiDragElements (line 3332) | function insertMultiDragElements(clonesInserted, rootEl) {
  function insertMultiDragClones (line 3348) | function insertMultiDragClones(elementsInserted, rootEl) {
  function removeMultiDragElements (line 3358) | function removeMultiDragElements() {

FILE: modular/sortable.complete.esm.js
  function _arrayLikeToArray (line 7) | function _arrayLikeToArray(r, a) {
  function _arrayWithoutHoles (line 12) | function _arrayWithoutHoles(r) {
  function _defineProperty (line 15) | function _defineProperty(e, r, t) {
  function _extends (line 23) | function _extends() {
  function _iterableToArray (line 32) | function _iterableToArray(r) {
  function _nonIterableSpread (line 35) | function _nonIterableSpread() {
  function ownKeys (line 38) | function ownKeys(e, r) {
  function _objectSpread2 (line 48) | function _objectSpread2(e) {
  function _objectWithoutProperties (line 59) | function _objectWithoutProperties(e, t) {
  function _objectWithoutPropertiesLoose (line 70) | function _objectWithoutPropertiesLoose(r, e) {
  function _toConsumableArray (line 79) | function _toConsumableArray(r) {
  function _toPrimitive (line 82) | function _toPrimitive(t, r) {
  function _toPropertyKey (line 92) | function _toPropertyKey(t) {
  function _typeof (line 96) | function _typeof(o) {
  function _unsupportedIterableToArray (line 105) | function _unsupportedIterableToArray(r, a) {
  function userAgent (line 115) | function userAgent(pattern) {
  function on (line 131) | function on(el, event, fn) {
  function off (line 134) | function off(el, event, fn) {
  function matches (line 137) | function matches( /**HTMLElement*/el, /**String*/selector) {
  function getParentOrHost (line 155) | function getParentOrHost(el) {
  function closest (line 158) | function closest( /**HTMLElement*/el, /**String*/selector, /**HTMLElemen...
  function toggleClass (line 172) | function toggleClass(el, name, state) {
  function css (line 182) | function css(el, prop, val) {
  function matrix (line 200) | function matrix(el, selfOnly) {
  function find (line 217) | function find(ctx, tagName, iterator) {
  function getWindowScrollingElement (line 231) | function getWindowScrollingElement() {
  function getRect (line 249) | function getRect(el, relativeToContainingBlock, relativeToNonStaticParen...
  function isScrolledPast (line 321) | function isScrolledPast(el, elSide, parentSide) {
  function getChild (line 349) | function getChild(el, childNum, options, includeDragEl) {
  function lastChild (line 371) | function lastChild(el, selector) {
  function index (line 386) | function index(el, selector) {
  function getRelativeScrollOffset (line 407) | function getRelativeScrollOffset(el) {
  function indexOfObject (line 429) | function indexOfObject(arr, obj) {
  function getParentAutoScrollElement (line 438) | function getParentAutoScrollElement(el, includeSelf) {
  function extend (line 457) | function extend(dst, src) {
  function isRectEqual (line 467) | function isRectEqual(rect1, rect2) {
  function throttle (line 471) | function throttle(callback, ms) {
  function cancelThrottle (line 487) | function cancelThrottle() {
  function scrollBy (line 491) | function scrollBy(el, x, y) {
  function clone (line 495) | function clone(el) {
  function setRect (line 506) | function setRect(el, rect) {
  function unsetRect (line 513) | function unsetRect(el) {
  function getChildContainingRectFromElement (line 520) | function getChildContainingRectFromElement(container, options, ghostEl) {
  function AnimationStateManager (line 539) | function AnimationStateManager() {
  function repaint (line 669) | function repaint(target) {
  function calculateRealTime (line 672) | function calculateRealTime(animatingRect, fromRect, toRect, options) {
  function dispatchEvent (line 763) | function dispatchEvent(_ref) {
  function _dispatchEvent (line 854) | function _dispatchEvent(info) {
  function toFn (line 970) | function toFn(value, pull) {
  function Sortable (line 1055) | function Sortable(el, options) {
  function dragOverEvent (line 1638) | function dragOverEvent(name, extra) {
  function capture (line 1658) | function capture() {
  function completed (line 1667) | function completed(insertion) {
  function changed (line 1720) | function changed() {
  function _globalDragOver (line 2204) | function _globalDragOver( /**Event*/evt) {
  function _onMove (line 2210) | function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, o...
  function _disableDraggable (line 2239) | function _disableDraggable(el) {
  function _unsilent (line 2242) | function _unsilent() {
  function _ghostIsFirst (line 2245) | function _ghostIsFirst(evt, vertical, sortable) {
  function _ghostIsLast (line 2251) | function _ghostIsLast(evt, vertical, sortable) {
  function _getSwapDirection (line 2257) | function _getSwapDirection(evt, target, targetRect, vertical, swapThresh...
  function _getInsertDirection (line 2304) | function _getInsertDirection(target) {
  function _generateId (line 2318) | function _generateId(el) {
  function _saveInputCheckedState (line 2327) | function _saveInputCheckedState(root) {
  function _nextTick (line 2336) | function _nextTick(fn) {
  function _cancelNextTick (line 2339) | function _cancelNextTick(id) {
  function AutoScrollPlugin (line 2421) | function AutoScrollPlugin() {
  function clearAutoScrolls (line 2524) | function clearAutoScrolls() {
  function clearPointerElemChangedInterval (line 2530) | function clearPointerElemChangedInterval() {
  function Revert (line 2641) | function Revert() {}
  function Remove (line 2671) | function Remove() {}
  function SwapPlugin (line 2688) | function SwapPlugin() {
  function swapNodes (line 2755) | function swapNodes(n1, n2) {
  function MultiDragPlugin (line 2783) | function MultiDragPlugin() {
  function insertMultiDragElements (line 3326) | function insertMultiDragElements(clonesInserted, rootEl) {
  function insertMultiDragClones (line 3342) | function insertMultiDragClones(elementsInserted, rootEl) {
  function removeMultiDragElements (line 3352) | function removeMultiDragElements() {

FILE: modular/sortable.core.esm.js
  function _arrayLikeToArray (line 7) | function _arrayLikeToArray(r, a) {
  function _arrayWithoutHoles (line 12) | function _arrayWithoutHoles(r) {
  function _defineProperty (line 15) | function _defineProperty(e, r, t) {
  function _extends (line 23) | function _extends() {
  function _iterableToArray (line 32) | function _iterableToArray(r) {
  function _nonIterableSpread (line 35) | function _nonIterableSpread() {
  function ownKeys (line 38) | function ownKeys(e, r) {
  function _objectSpread2 (line 48) | function _objectSpread2(e) {
  function _objectWithoutProperties (line 59) | function _objectWithoutProperties(e, t) {
  function _objectWithoutPropertiesLoose (line 70) | function _objectWithoutPropertiesLoose(r, e) {
  function _toConsumableArray (line 79) | function _toConsumableArray(r) {
  function _toPrimitive (line 82) | function _toPrimitive(t, r) {
  function _toPropertyKey (line 92) | function _toPropertyKey(t) {
  function _typeof (line 96) | function _typeof(o) {
  function _unsupportedIterableToArray (line 105) | function _unsupportedIterableToArray(r, a) {
  function userAgent (line 115) | function userAgent(pattern) {
  function on (line 131) | function on(el, event, fn) {
  function off (line 134) | function off(el, event, fn) {
  function matches (line 137) | function matches( /**HTMLElement*/el, /**String*/selector) {
  function getParentOrHost (line 155) | function getParentOrHost(el) {
  function closest (line 158) | function closest( /**HTMLElement*/el, /**String*/selector, /**HTMLElemen...
  function toggleClass (line 172) | function toggleClass(el, name, state) {
  function css (line 182) | function css(el, prop, val) {
  function matrix (line 200) | function matrix(el, selfOnly) {
  function find (line 217) | function find(ctx, tagName, iterator) {
  function getWindowScrollingElement (line 231) | function getWindowScrollingElement() {
  function getRect (line 249) | function getRect(el, relativeToContainingBlock, relativeToNonStaticParen...
  function isScrolledPast (line 321) | function isScrolledPast(el, elSide, parentSide) {
  function getChild (line 349) | function getChild(el, childNum, options, includeDragEl) {
  function lastChild (line 371) | function lastChild(el, selector) {
  function index (line 386) | function index(el, selector) {
  function getRelativeScrollOffset (line 407) | function getRelativeScrollOffset(el) {
  function indexOfObject (line 429) | function indexOfObject(arr, obj) {
  function getParentAutoScrollElement (line 438) | function getParentAutoScrollElement(el, includeSelf) {
  function extend (line 457) | function extend(dst, src) {
  function isRectEqual (line 467) | function isRectEqual(rect1, rect2) {
  function throttle (line 471) | function throttle(callback, ms) {
  function cancelThrottle (line 487) | function cancelThrottle() {
  function scrollBy (line 491) | function scrollBy(el, x, y) {
  function clone (line 495) | function clone(el) {
  function setRect (line 506) | function setRect(el, rect) {
  function unsetRect (line 513) | function unsetRect(el) {
  function getChildContainingRectFromElement (line 520) | function getChildContainingRectFromElement(container, options, ghostEl) {
  function AnimationStateManager (line 539) | function AnimationStateManager() {
  function repaint (line 669) | function repaint(target) {
  function calculateRealTime (line 672) | function calculateRealTime(animatingRect, fromRect, toRect, options) {
  function dispatchEvent (line 763) | function dispatchEvent(_ref) {
  function _dispatchEvent (line 854) | function _dispatchEvent(info) {
  function toFn (line 970) | function toFn(value, pull) {
  function Sortable (line 1055) | function Sortable(el, options) {
  function dragOverEvent (line 1638) | function dragOverEvent(name, extra) {
  function capture (line 1658) | function capture() {
  function completed (line 1667) | function completed(insertion) {
  function changed (line 1720) | function changed() {
  function _globalDragOver (line 2204) | function _globalDragOver( /**Event*/evt) {
  function _onMove (line 2210) | function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, o...
  function _disableDraggable (line 2239) | function _disableDraggable(el) {
  function _unsilent (line 2242) | function _unsilent() {
  function _ghostIsFirst (line 2245) | function _ghostIsFirst(evt, vertical, sortable) {
  function _ghostIsLast (line 2251) | function _ghostIsLast(evt, vertical, sortable) {
  function _getSwapDirection (line 2257) | function _getSwapDirection(evt, target, targetRect, vertical, swapThresh...
  function _getInsertDirection (line 2304) | function _getInsertDirection(target) {
  function _generateId (line 2318) | function _generateId(el) {
  function _saveInputCheckedState (line 2327) | function _saveInputCheckedState(root) {
  function _nextTick (line 2336) | function _nextTick(fn) {
  function _cancelNextTick (line 2339) | function _cancelNextTick(id) {
  function AutoScrollPlugin (line 2421) | function AutoScrollPlugin() {
  function clearAutoScrolls (line 2524) | function clearAutoScrolls() {
  function clearPointerElemChangedInterval (line 2530) | function clearPointerElemChangedInterval() {
  function Revert (line 2641) | function Revert() {}
  function Remove (line 2671) | function Remove() {}
  function SwapPlugin (line 2689) | function SwapPlugin() {
  function swapNodes (line 2756) | function swapNodes(n1, n2) {
  function MultiDragPlugin (line 2784) | function MultiDragPlugin() {
  function insertMultiDragElements (line 3327) | function insertMultiDragElements(clonesInserted, rootEl) {
  function insertMultiDragClones (line 3343) | function insertMultiDragClones(elementsInserted, rootEl) {
  function removeMultiDragElements (line 3353) | function removeMultiDragElements() {

FILE: modular/sortable.esm.js
  function _arrayLikeToArray (line 7) | function _arrayLikeToArray(r, a) {
  function _arrayWithoutHoles (line 12) | function _arrayWithoutHoles(r) {
  function _defineProperty (line 15) | function _defineProperty(e, r, t) {
  function _extends (line 23) | function _extends() {
  function _iterableToArray (line 32) | function _iterableToArray(r) {
  function _nonIterableSpread (line 35) | function _nonIterableSpread() {
  function ownKeys (line 38) | function ownKeys(e, r) {
  function _objectSpread2 (line 48) | function _objectSpread2(e) {
  function _objectWithoutProperties (line 59) | function _objectWithoutProperties(e, t) {
  function _objectWithoutPropertiesLoose (line 70) | function _objectWithoutPropertiesLoose(r, e) {
  function _toConsumableArray (line 79) | function _toConsumableArray(r) {
  function _toPrimitive (line 82) | function _toPrimitive(t, r) {
  function _toPropertyKey (line 92) | function _toPropertyKey(t) {
  function _typeof (line 96) | function _typeof(o) {
  function _unsupportedIterableToArray (line 105) | function _unsupportedIterableToArray(r, a) {
  function userAgent (line 115) | function userAgent(pattern) {
  function on (line 131) | function on(el, event, fn) {
  function off (line 134) | function off(el, event, fn) {
  function matches (line 137) | function matches( /**HTMLElement*/el, /**String*/selector) {
  function getParentOrHost (line 155) | function getParentOrHost(el) {
  function closest (line 158) | function closest( /**HTMLElement*/el, /**String*/selector, /**HTMLElemen...
  function toggleClass (line 172) | function toggleClass(el, name, state) {
  function css (line 182) | function css(el, prop, val) {
  function matrix (line 200) | function matrix(el, selfOnly) {
  function find (line 217) | function find(ctx, tagName, iterator) {
  function getWindowScrollingElement (line 231) | function getWindowScrollingElement() {
  function getRect (line 249) | function getRect(el, relativeToContainingBlock, relativeToNonStaticParen...
  function isScrolledPast (line 321) | function isScrolledPast(el, elSide, parentSide) {
  function getChild (line 349) | function getChild(el, childNum, options, includeDragEl) {
  function lastChild (line 371) | function lastChild(el, selector) {
  function index (line 386) | function index(el, selector) {
  function getRelativeScrollOffset (line 407) | function getRelativeScrollOffset(el) {
  function indexOfObject (line 429) | function indexOfObject(arr, obj) {
  function getParentAutoScrollElement (line 438) | function getParentAutoScrollElement(el, includeSelf) {
  function extend (line 457) | function extend(dst, src) {
  function isRectEqual (line 467) | function isRectEqual(rect1, rect2) {
  function throttle (line 471) | function throttle(callback, ms) {
  function cancelThrottle (line 487) | function cancelThrottle() {
  function scrollBy (line 491) | function scrollBy(el, x, y) {
  function clone (line 495) | function clone(el) {
  function setRect (line 506) | function setRect(el, rect) {
  function unsetRect (line 513) | function unsetRect(el) {
  function getChildContainingRectFromElement (line 520) | function getChildContainingRectFromElement(container, options, ghostEl) {
  function AnimationStateManager (line 539) | function AnimationStateManager() {
  function repaint (line 669) | function repaint(target) {
  function calculateRealTime (line 672) | function calculateRealTime(animatingRect, fromRect, toRect, options) {
  function dispatchEvent (line 763) | function dispatchEvent(_ref) {
  function _dispatchEvent (line 854) | function _dispatchEvent(info) {
  function toFn (line 970) | function toFn(value, pull) {
  function Sortable (line 1055) | function Sortable(el, options) {
  function dragOverEvent (line 1638) | function dragOverEvent(name, extra) {
  function capture (line 1658) | function capture() {
  function completed (line 1667) | function completed(insertion) {
  function changed (line 1720) | function changed() {
  function _globalDragOver (line 2204) | function _globalDragOver( /**Event*/evt) {
  function _onMove (line 2210) | function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, o...
  function _disableDraggable (line 2239) | function _disableDraggable(el) {
  function _unsilent (line 2242) | function _unsilent() {
  function _ghostIsFirst (line 2245) | function _ghostIsFirst(evt, vertical, sortable) {
  function _ghostIsLast (line 2251) | function _ghostIsLast(evt, vertical, sortable) {
  function _getSwapDirection (line 2257) | function _getSwapDirection(evt, target, targetRect, vertical, swapThresh...
  function _getInsertDirection (line 2304) | function _getInsertDirection(target) {
  function _generateId (line 2318) | function _generateId(el) {
  function _saveInputCheckedState (line 2327) | function _saveInputCheckedState(root) {
  function _nextTick (line 2336) | function _nextTick(fn) {
  function _cancelNextTick (line 2339) | function _cancelNextTick(id) {
  function AutoScrollPlugin (line 2421) | function AutoScrollPlugin() {
  function clearAutoScrolls (line 2524) | function clearAutoScrolls() {
  function clearPointerElemChangedInterval (line 2530) | function clearPointerElemChangedInterval() {
  function Revert (line 2641) | function Revert() {}
  function Remove (line 2671) | function Remove() {}
  function SwapPlugin (line 2688) | function SwapPlugin() {
  function swapNodes (line 2755) | function swapNodes(n1, n2) {
  function MultiDragPlugin (line 2783) | function MultiDragPlugin() {
  function insertMultiDragElements (line 3326) | function insertMultiDragElements(clonesInserted, rootEl) {
  function insertMultiDragClones (line 3342) | function insertMultiDragClones(elementsInserted, rootEl) {
  function removeMultiDragElements (line 3352) | function removeMultiDragElements() {

FILE: plugins/AutoScroll/AutoScroll.js
  function AutoScrollPlugin (line 27) | function AutoScrollPlugin() {
  function clearAutoScrolls (line 153) | function clearAutoScrolls() {
  function clearPointerElemChangedInterval (line 160) | function clearPointerElemChangedInterval() {

FILE: plugins/MultiDrag/MultiDrag.js
  function MultiDragPlugin (line 29) | function MultiDragPlugin() {
  function insertMultiDragElements (line 599) | function insertMultiDragElements(clonesInserted, rootEl) {
  function insertMultiDragClones (line 615) | function insertMultiDragClones(elementsInserted, rootEl) {
  function removeMultiDragElements (line 626) | function removeMultiDragElements() {

FILE: plugins/OnSpill/OnSpill.js
  function Revert (line 25) | function Revert() {}
  method dragStart (line 29) | dragStart({ oldDraggableIndex }) {
  method onSpill (line 32) | onSpill({ dragEl, putSortable }) {
  function Remove (line 57) | function Remove() {}
  method onSpill (line 60) | onSpill({ dragEl, putSortable }) {

FILE: plugins/Swap/Swap.js
  function SwapPlugin (line 9) | function SwapPlugin() {
  function swapNodes (line 73) | function swapNodes(n1, n2) {

FILE: src/Animation.js
  function AnimationStateManager (line 4) | function AnimationStateManager() {
  function repaint (line 165) | function repaint(target) {
  function calculateRealTime (line 170) | function calculateRealTime(animatingRect, fromRect, toRect, options) {

FILE: src/BrowserInfo.js
  function userAgent (line 1) | function userAgent(pattern) {
  constant IOS (line 11) | const IOS = userAgent(/iP(ad|od|hone)/i);

FILE: src/EventDispatcher.js
  function dispatchEvent (line 5) | function dispatchEvent(

FILE: src/PluginManager.js
  method mount (line 8) | mount(plugin) {
  method pluginEvent (line 24) | pluginEvent(eventName, sortable, evt) {
  method initializePlugins (line 49) | initializePlugins(sortable, el, defaults, options) {
  method getEventProperties (line 71) | getEventProperties(name, sortable) {
  method modifyOption (line 80) | modifyOption(sortable, name, value) {

FILE: src/Sortable.js
  method cloneNowHidden (line 67) | cloneNowHidden() {
  method cloneNowShown (line 70) | cloneNowShown() {
  method dispatchSortableEvent (line 74) | dispatchSortableEvent(name) {
  function _dispatchEvent (line 82) | function _dispatchEvent(info) {
  function toFn (line 248) | function toFn(value, pull) {
  function Sortable (line 349) | function Sortable(el, options) {
  function dragOverEvent (line 1028) | function dragOverEvent(name, extra) {
  function capture (line 1049) | function capture() {
  function completed (line 1059) | function completed(insertion) {
  function changed (line 1116) | function changed() {
  function _globalDragOver (line 1762) | function _globalDragOver(/**Event*/evt) {
  function onMove (line 1769) | function onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, or...
  function _disableDraggable (line 1804) | function _disableDraggable(el) {
  function _unsilent (line 1808) | function _unsilent() {
  function _ghostIsFirst (line 1812) | function _ghostIsFirst(evt, vertical, sortable) {
  function _ghostIsLast (line 1822) | function _ghostIsLast(evt, vertical, sortable) {
  function _getSwapDirection (line 1832) | function _getSwapDirection(evt, target, targetRect, vertical, swapThresh...
  function _getInsertDirection (line 1909) | function _getInsertDirection(target) {
  function _generateId (line 1924) | function _generateId(el) {
  function _saveInputCheckedState (line 1936) | function _saveInputCheckedState(root) {
  function _nextTick (line 1948) | function _nextTick(fn) {
  function _cancelNextTick (line 1952) | function _cancelNextTick(id) {

FILE: src/utils.js
  function on (line 9) | function on(el, event, fn) {
  function off (line 14) | function off(el, event, fn) {
  function matches (line 18) | function matches(/**HTMLElement*/el, /**String*/selector) {
  function getParentOrHost (line 40) | function getParentOrHost(el) {
  function closest (line 46) | function closest(/**HTMLElement*/el, /**String*/selector, /**HTMLElement...
  constant R_SPACE (line 71) | const R_SPACE = /\s+/g;
  function toggleClass (line 73) | function toggleClass(el, name, state) {
  function css (line 86) | function css(el, prop, val) {
  function matrix (line 110) | function matrix(el, selfOnly) {
  function find (line 131) | function find(ctx, tagName, iterator) {
  function getWindowScrollingElement (line 149) | function getWindowScrollingElement() {
  function getRect (line 169) | function getRect(el, relativeToContainingBlock, relativeToNonStaticParen...
  function getContentRect (line 261) | function getContentRect(el) {
  function isScrolledPast (line 284) | function isScrolledPast(el, elSide, parentSide) {
  function getChild (line 319) | function getChild(el, childNum, options, includeDragEl) {
  function lastChild (line 348) | function lastChild(el, selector) {
  function index (line 373) | function index(el, selector) {
  function getRelativeScrollOffset (line 396) | function getRelativeScrollOffset(el) {
  function indexOfObject (line 421) | function indexOfObject(arr, obj) {
  function getParentAutoScrollElement (line 432) | function getParentAutoScrollElement(el, includeSelf) {
  function extend (line 458) | function extend(dst, src) {
  function isRectEqual (line 471) | function isRectEqual(rect1, rect2) {
  function throttle (line 480) | function throttle(callback, ms) {
  function cancelThrottle (line 500) | function cancelThrottle() {
  function scrollBy (line 506) | function scrollBy(el, x, y) {
  function clone (line 512) | function clone(el) {
  function setRect (line 528) | function setRect(el, rect) {
  function unsetRect (line 536) | function unsetRect(el) {
  function getChildContainingRectFromElement (line 544) | function getChildContainingRectFromElement(container, options, ghostEl) {

FILE: st/app.js
  function renderThresholdWidth (line 103) | function renderThresholdWidth(evt) {
  function renderDirection (line 145) | function renderDirection(evt) {

FILE: st/prettify/prettify.js
  function T (line 18) | function T(a){function d(e){var a=e.charCodeAt(0);if(92!==a)return a;var...
  function U (line 22) | function U(a,d){function f(a){var b=a.nodeType;if(1==b){if(!c.test(a.cla...
  function J (line 23) | function J(a,d,f,c,m){f&&(a={h:a,l:1,j:null,m:null,a:f,c:null,i:d,g:null...
  function V (line 23) | function V(a){for(var d=void 0,f=a.firstChild;f;f=f.nextSibling)var c=f....
  function G (line 23) | function G(a,d){function f(a){for(var l=a.i,n=a.h,b=[l,"pln"],p=0,q=a.a....
  function x (line 25) | function x(a){var d=[],f=[];a.tripleQuotedStrings?d.push(["str",/^(?:\'\...
  function L (line 29) | function L(a,d,f){function c(a){var b=a.nodeType;if(1==b&&!t.test(a.clas...
  function t (line 31) | function t(a,d){for(var f=d.length;0<=--f;){var c=d[f];I.hasOwnProperty(...
  function K (line 31) | function K(a,d){a&&I.hasOwnProperty(a)||(a=/^\s*</.test(d)?
  function M (line 32) | function M(a){var d=a.j;try{var f=U(a.h,a.l),c=f.a;a.a=c;a.c=f.c;a.i=0;K...
  function f (line 43) | function f(){for(var c=D.PR_SHOULD_USE_CONTINUATION?b.now()+250:Infinity...

FILE: st/prettify/run_prettify.js
  function aa (line 31) | function aa(g){function r(){try{L.doScroll("left")}catch(ba){k.setTimeou...
  function T (line 32) | function T(){U&&aa(function(){var g=M.length;ca(g?function(){for(var r=0...
  function r (line 34) | function r(l){if(l!==x){var k=z.createElement("link");k.rel="stylesheet"...
  function r (line 35) | function r(a){function d(e){var a=e.charCodeAt(0);if(92!==a)return a;var...
  function l (line 39) | function l(a,d){function f(a){var b=a.nodeType;if(1==b){if(!c.test(a.cla...
  function k (line 40) | function k(a,d,f,c,g){f&&(a={h:a,l:1,j:null,m:null,a:f,c:null,i:d,g:null...
  function z (line 40) | function z(a){for(var d=void 0,f=a.firstChild;f;f=
  function E (line 41) | function E(a,d){function f(a){for(var q=a.i,r=a.h,b=[q,"pln"],t=0,A=a.a....
  function v (line 42) | function v(a){var d=
  function B (line 46) | function B(a,d,f){function c(a){var b=
  function n (line 49) | function n(a,d){for(var f=d.length;0<=--f;){var c=d[f];V.hasOwnProperty(...
  function F (line 49) | function F(a,d){a&&V.hasOwnProperty(a)||(a=/^\s*</.test(d)?"default-mark...
  function H (line 49) | function H(a){var d=a.j;try{var f=l(a.h,a.l),c=f.a;a.a=c;a.c=f.c;a.i=0;F...
  function f (line 61) | function f(){for(var c=Q.PR_SHOULD_USE_CONTINUATION?b.now()+250:Infinity...
Condensed preview — 64 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (781K chars).
[
  {
    "path": ".circleci/config.yml",
    "chars": 691,
    "preview": "version: 2.0\njobs:\n  build:\n    docker:\n      - image: circleci/node:10.16-browsers\n    steps:\n      - checkout\n\n      -"
  },
  {
    "path": ".editorconfig",
    "chars": 219,
    "preview": "# editorconfig.org\nroot = true\n\n[*]\nindent_style = tab\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.md",
    "chars": 1943,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: \"[bug] \"\nlabels: \"\"\nassignees: \"\"\n---\n\n<!--\n\nPLEAS"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/custom-template.md",
    "chars": 1417,
    "preview": "---\nname: Custom issue template\nabout: Not a feature request or a bug report. Usually questions, queries or concerns\ntit"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature-request.md",
    "chars": 1357,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: \"[feature] \"\nlabels: \"\"\nassignees: \"\"\n---\n\n<!--"
  },
  {
    "path": ".gitignore",
    "chars": 56,
    "preview": "node_modules\nmock.png\n.*.sw*\n.build*\njquery.fn.*\n.idea/\n"
  },
  {
    "path": ".jshintrc",
    "chars": 398,
    "preview": "{\n\t\"strict\": false,\n\t\"newcap\": false,\n\t\"node\": true,\n\t\"expr\": true,\n\t\"supernew\": true,\n\t\"laxbreak\": true,\n\t\"esversion\": "
  },
  {
    "path": ".testcaferc.json",
    "chars": 96,
    "preview": "{\n\t\"speed\": 0.4,\n\t\"reporter\": {\n\t\t\"name\": \"xunit\",\n\t\t\"output\": \"/tmp/test-results/res.xml\"\n\t}\n}\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 976,
    "preview": "# Contribution Guidelines\n\n### Issue\n\n 1. Try [master](https://github.com/SortableJS/Sortable/tree/master/)-branch, perh"
  },
  {
    "path": "LICENSE",
    "chars": 1085,
    "preview": "MIT License\n\nCopyright (c) 2019 All contributors to Sortable\n\nPermission is hereby granted, free of charge, to any perso"
  },
  {
    "path": "README.md",
    "chars": 27216,
    "preview": "# Sortable &nbsp; [![Financial Contributors on Open Collective](https://opencollective.com/Sortable/all/badge.svg?label="
  },
  {
    "path": "Sortable.js",
    "chars": 126176,
    "preview": "/**!\n * Sortable 1.15.7\n * @author\tRubaXa   <trash@rubaxa.org>\n * @author\towenm    <owen23355@gmail.com>\n * @license MIT"
  },
  {
    "path": "babel.config.js",
    "chars": 377,
    "preview": "module.exports = function(api) {\n\tapi.cache(true);\n\n\tlet presets;\n\n\tif (process.env.NODE_ENV === 'es') {\n\t\tpresets = [\n\t"
  },
  {
    "path": "bower.json",
    "chars": 684,
    "preview": "{\n  \"name\": \"Sortable\",\n  \"main\": [\n    \"Sortable.js\"\n  ],\n  \"homepage\": \"http://SortableJS.github.io/Sortable/\",\n  \"aut"
  },
  {
    "path": "entry/entry-complete.js",
    "chars": 214,
    "preview": "import Sortable from './entry-defaults.js';\nimport Swap from '../plugins/Swap';\nimport MultiDrag from '../plugins/MultiD"
  },
  {
    "path": "entry/entry-core.js",
    "chars": 330,
    "preview": "import Sortable from '../src/Sortable.js';\nimport AutoScroll from '../plugins/AutoScroll';\nimport OnSpill from '../plugi"
  },
  {
    "path": "entry/entry-defaults.js",
    "chars": 409,
    "preview": "import Sortable from '../src/Sortable.js';\nimport AutoScroll from '../plugins/AutoScroll';\nimport { RemoveOnSpill, Rever"
  },
  {
    "path": "index.html",
    "chars": 18482,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n\t<link rel=\"icon\" type=\"image/png\" href=\"st/og-image.png\">\n\t<title>SortableJS</title>\n\t<li"
  },
  {
    "path": "modular/sortable.complete.esm.js",
    "chars": 119406,
    "preview": "/**!\n * Sortable 1.15.7\n * @author\tRubaXa   <trash@rubaxa.org>\n * @author\towenm    <owen23355@gmail.com>\n * @license MIT"
  },
  {
    "path": "modular/sortable.core.esm.js",
    "chars": 119403,
    "preview": "/**!\n * Sortable 1.15.7\n * @author\tRubaXa   <trash@rubaxa.org>\n * @author\towenm    <owen23355@gmail.com>\n * @license MIT"
  },
  {
    "path": "modular/sortable.esm.js",
    "chars": 119403,
    "preview": "/**!\n * Sortable 1.15.7\n * @author\tRubaXa   <trash@rubaxa.org>\n * @author\towenm    <owen23355@gmail.com>\n * @license MIT"
  },
  {
    "path": "package.json",
    "chars": 1708,
    "preview": "{\n\t\"name\": \"sortablejs\",\n\t\"exportName\": \"Sortable\",\n\t\"version\": \"1.15.7\",\n\t\"devDependencies\": {\n\t\t\"@babel/core\": \"^7.4.4"
  },
  {
    "path": "plugins/AutoScroll/AutoScroll.js",
    "chars": 7831,
    "preview": "import {\n\ton,\n\toff,\n\tcss,\n\tthrottle,\n\tcancelThrottle,\n\tscrollBy,\n\tgetParentAutoScrollElement,\n\texpando,\n\tgetRect,\n\tgetWi"
  },
  {
    "path": "plugins/AutoScroll/README.md",
    "chars": 3822,
    "preview": "## AutoScroll\nThis plugin allows for the page to automatically scroll during dragging near a scrollable element's edge o"
  },
  {
    "path": "plugins/AutoScroll/index.js",
    "chars": 43,
    "preview": "export { default } from './AutoScroll.js';\n"
  },
  {
    "path": "plugins/MultiDrag/MultiDrag.js",
    "chars": 17959,
    "preview": "import {\n\ttoggleClass,\n\tgetRect,\n\tindex,\n\tclosest,\n\ton,\n\toff,\n\tclone,\n\tcss,\n\tsetRect,\n\tunsetRect,\n\tmatrix,\n\texpando\n} fr"
  },
  {
    "path": "plugins/MultiDrag/README.md",
    "chars": 2579,
    "preview": "## MultiDrag Plugin\nThis plugin allows users to select multiple items within a sortable at once, and drag them as one it"
  },
  {
    "path": "plugins/MultiDrag/index.js",
    "chars": 42,
    "preview": "export { default } from './MultiDrag.js';\n"
  },
  {
    "path": "plugins/OnSpill/OnSpill.js",
    "chars": 1757,
    "preview": "import { getChild } from '../../src/utils.js';\n\n\nconst drop = function({\n\toriginalEvent,\n\tputSortable,\n\tdragEl,\n\tactiveS"
  },
  {
    "path": "plugins/OnSpill/README.md",
    "chars": 1235,
    "preview": "# OnSpill Plugins\nThis file contains two seperate plugins, RemoveOnSpill and RevertOnSpill. They can be imported individ"
  },
  {
    "path": "plugins/OnSpill/index.js",
    "chars": 70,
    "preview": "export { default, RemoveOnSpill, RevertOnSpill } from './OnSpill.js';\n"
  },
  {
    "path": "plugins/README.md",
    "chars": 14539,
    "preview": "# Creating Sortable Plugins\nSortable plugins are plugins that can be directly mounted to the Sortable class. They are a "
  },
  {
    "path": "plugins/Swap/README.md",
    "chars": 1085,
    "preview": "## Swap Plugin\nThis plugin modifies the behaviour of Sortable to allow for items to be swapped with eachother rather tha"
  },
  {
    "path": "plugins/Swap/Swap.js",
    "chars": 1958,
    "preview": "import {\n\ttoggleClass,\n\tindex\n} from '../../src/utils.js';\n\nlet lastSwapEl;\n\n\nfunction SwapPlugin() {\n\tfunction Swap() {"
  },
  {
    "path": "plugins/Swap/index.js",
    "chars": 37,
    "preview": "export { default } from './Swap.js';\n"
  },
  {
    "path": "scripts/banner.js",
    "chars": 193,
    "preview": "import { version } from '../package.json';\n\nexport default `/**!\n * Sortable ${ version }\n * @author\tRubaXa   <trash@rub"
  },
  {
    "path": "scripts/build.js",
    "chars": 281,
    "preview": "import babel from 'rollup-plugin-babel';\nimport json from 'rollup-plugin-json';\nimport resolve from 'rollup-plugin-node-"
  },
  {
    "path": "scripts/esm-build.js",
    "chars": 591,
    "preview": "import build from './build.js';\n\nexport default ([\n\t{\n\t\tinput: 'entry/entry-core.js',\n\t\toutput: Object.assign({}, build."
  },
  {
    "path": "scripts/minify.js",
    "chars": 337,
    "preview": "const UglifyJS = require('uglify-js'),\n\tfs = require('fs'),\n \tpackage = require('../package.json');\n\nconst banner = `/*!"
  },
  {
    "path": "scripts/test-compat.js",
    "chars": 920,
    "preview": "const createTestCafe = require('testcafe');\n// Testcafe cannot test on IE < 11\n// Testcafe testing on Chrome Android is "
  },
  {
    "path": "scripts/test.js",
    "chars": 463,
    "preview": "const createTestCafe = require('testcafe');\n\nlet testcafe;\nlet runner;\nlet failedCount;\n\n\ncreateTestCafe().then((tc) => "
  },
  {
    "path": "scripts/umd-build.js",
    "chars": 282,
    "preview": "import build from './build.js';\n\n\nexport default ([\n\t{\n\t\tinput: 'entry/entry-complete.js',\n\t\toutput: Object.assign({}, b"
  },
  {
    "path": "src/Animation.js",
    "chars": 4972,
    "preview": "import { getRect, css, matrix, isRectEqual, indexOfObject } from './utils.js';\nimport Sortable from './Sortable.js';\n\nex"
  },
  {
    "path": "src/BrowserInfo.js",
    "chars": 557,
    "preview": "function userAgent(pattern) {\n\tif (typeof window !== 'undefined' && window.navigator) {\n\t\treturn !!/*@__PURE__*/navigato"
  },
  {
    "path": "src/EventDispatcher.js",
    "chars": 1474,
    "preview": "import { IE11OrLess, Edge } from './BrowserInfo.js';\nimport { expando } from './utils.js';\nimport PluginManager from './"
  },
  {
    "path": "src/PluginManager.js",
    "chars": 2781,
    "preview": "let plugins = [];\n\nconst defaults = {\n\tinitializeByDefault: true\n};\n\nexport default {\n\tmount(plugin) {\n\t\t// Set default "
  },
  {
    "path": "src/Sortable.js",
    "chars": 51500,
    "preview": "/**!\n * Sortable\n * @author\tRubaXa   <trash@rubaxa.org>\n * @author\towenm    <owen23355@gmail.com>\n * @license MIT\n */\n\ni"
  },
  {
    "path": "src/utils.js",
    "chars": 14632,
    "preview": "import { IE11OrLess } from './BrowserInfo.js';\nimport Sortable from './Sortable.js';\n\nconst captureMode = {\n\tcapture: fa"
  },
  {
    "path": "st/app.js",
    "chars": 6278,
    "preview": "var example1 = document.getElementById('example1'),\n\texample2Left = document.getElementById('example2-left'),\n\texample2R"
  },
  {
    "path": "st/iframe/frame.html",
    "chars": 800,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n\t<meta charset=\"utf-8\">\n</head>\n<body>\n\n<!-- Latest compiled and minified CSS -->\n<link re"
  },
  {
    "path": "st/iframe/index.html",
    "chars": 1171,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n\t<meta charset=\"utf-8\">\n\t<title>IFrame playground</title>\n</head>\n<body>\n\n\n<!-- Latest com"
  },
  {
    "path": "st/prettify/prettify.css",
    "chars": 655,
    "preview": ".pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.clo,.opn,"
  },
  {
    "path": "st/prettify/prettify.js",
    "chars": 15655,
    "preview": "!function(){/*\n\n Copyright (C) 2006 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you m"
  },
  {
    "path": "st/prettify/run_prettify.js",
    "chars": 18428,
    "preview": "!function(){/*\n\n Copyright (C) 2013 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you m"
  },
  {
    "path": "st/theme.css",
    "chars": 4893,
    "preview": "body {\n\tfont-family: Helvetica Neue, Helvetica, Arial;\n\tbackground: rgb(244,215,201); /* Old browsers */\n\tbackground: -m"
  },
  {
    "path": "tests/Sortable.compat.test.js",
    "chars": 1326,
    "preview": "import { Selector } from 'testcafe';\n\n\nfixture `Simple Sorting`\n\t.page `./single-list.html`;\n\nlet list1 = Selector('#lis"
  },
  {
    "path": "tests/Sortable.test.js",
    "chars": 14111,
    "preview": "import { Selector } from 'testcafe';\nconst itemHeight = 54; // px\nconst leeway = 1;\n\n\nfixture `Simple Sorting`\n\t.page `."
  },
  {
    "path": "tests/dual-list.html",
    "chars": 643,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n\t<title></title>\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"./style.css\">\n</head>\n<body"
  },
  {
    "path": "tests/empty-list.html",
    "chars": 555,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n\t<title></title>\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"./style.css\">\n</head>\n<body"
  },
  {
    "path": "tests/filter.html",
    "chars": 459,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n\t<title></title>\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"./style.css\">\n</head>\n<body"
  },
  {
    "path": "tests/handles.html",
    "chars": 590,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n\t<title></title>\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"./style.css\">\n</head>\n<body"
  },
  {
    "path": "tests/nested.html",
    "chars": 1086,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n\t<title></title>\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"./style.css\">\n</head>\n<body"
  },
  {
    "path": "tests/single-list.html",
    "chars": 415,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n\t<title></title>\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"./style.css\">\n</head>\n<body"
  },
  {
    "path": "tests/style.css",
    "chars": 257,
    "preview": ".list > div {\n\tmin-height: 50px;\n\tborder-style: solid;\n\tborder-width: 2px;\n\ttext-align: center;\n\tline-height: 50px;\n\tfon"
  }
]

About this extraction

This page contains the full source code of the SortableJS/Sortable GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 64 files (723.9 KB), approximately 192.6k tokens, and a symbol index with 411 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!