diff --git a/Moonlight/Pages/_Layout.cshtml b/Moonlight/Pages/_Layout.cshtml
index c840ed2c..968aaf46 100644
--- a/Moonlight/Pages/_Layout.cshtml
+++ b/Moonlight/Pages/_Layout.cshtml
@@ -41,7 +41,6 @@
-
@@ -50,8 +49,8 @@
-
-
+
+
@@ -96,20 +95,21 @@
-
-
+
+
-
+
-
-
+
+
+
@@ -122,8 +122,8 @@
moonlight.loading.registerXterm();
-
-
+
+
diff --git a/Moonlight/wwwroot/assets/css/snow.css b/Moonlight/wwwroot/assets/css/snow.css
deleted file mode 100644
index b3fb1310..00000000
--- a/Moonlight/wwwroot/assets/css/snow.css
+++ /dev/null
@@ -1,9 +0,0 @@
-.snow-canvas {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- z-index: -1;
- pointer-events: none;
-}
\ No newline at end of file
diff --git a/Moonlight/wwwroot/assets/css/toastr.css b/Moonlight/wwwroot/assets/css/toastr.css
new file mode 100644
index 00000000..48a74a5f
--- /dev/null
+++ b/Moonlight/wwwroot/assets/css/toastr.css
@@ -0,0 +1,372 @@
+.toastr-title {
+ font-weight: bold;
+}
+
+.toastr-message {
+ -ms-word-wrap: break-word;
+ word-wrap: break-word;
+}
+
+.toastr-message a,
+.toastr-message label {
+ color: #FFFFFF;
+}
+
+.toastr-message a:hover {
+ color: #CCCCCC;
+ text-decoration: none;
+}
+
+.toastr-close-button {
+ position: relative;
+ right: -0.3em;
+ top: -0.3em;
+ float: right;
+ font-size: 20px;
+ font-weight: bold;
+ color: #FFFFFF;
+ -webkit-text-shadow: 0 1px 0 #ffffff;
+ text-shadow: 0 1px 0 #ffffff;
+ opacity: 0.8;
+ -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
+ filter: alpha(opacity=80);
+ line-height: 1;
+}
+
+.toastr-close-button:hover,
+.toastr-close-button:focus {
+ color: #000000;
+ text-decoration: none;
+ cursor: pointer;
+ opacity: 0.4;
+ -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40);
+ filter: alpha(opacity=40);
+}
+
+.rtl .toastr-close-button {
+ left: -0.3em;
+ float: left;
+ right: 0.3em;
+}
+
+/*Additional properties for button version
+ iOS requires the button element instead of an anchor tag.
+ If you want the anchor version, it requires `href="#"`.*/
+button.toastr-close-button {
+ padding: 0;
+ cursor: pointer;
+ background: transparent;
+ border: 0;
+ -webkit-appearance: none;
+}
+
+.toastr-top-center {
+ top: 0;
+ right: 0;
+ width: 100%;
+}
+
+.toastr-top-center-nav-margin {
+ top: 65px;
+ right: 0;
+ width: 100%;
+}
+
+.toastr-bottom-center {
+ bottom: 0;
+ right: 0;
+ width: 100%;
+}
+
+.toastr-top-full-width {
+ top: 0;
+ right: 0;
+ width: 100%;
+}
+
+.toastr-top-full-width-nav-margin {
+ top: 65px;
+ right: 0;
+ width: 100%;
+}
+
+.toastr-bottom-full-width {
+ bottom: 0;
+ right: 0;
+ width: 100%;
+}
+
+.toastr-top-left {
+ top: 12px;
+ left: 12px;
+}
+
+.toastr-top-left-nav-margin {
+ top: 65px;
+ left: 12px;
+}
+
+.toastr-top-right {
+ top: 12px;
+ right: 12px;
+}
+
+.toastr-top-right-nav-margin {
+ top: 65px;
+ right: 12px;
+}
+
+.toastr-bottom-right {
+ right: 12px;
+ bottom: 12px;
+}
+
+.toastr-bottom-left {
+ bottom: 12px;
+ left: 12px;
+}
+
+#toastr-container {
+ position: fixed;
+ z-index: 999999;
+ pointer-events: none;
+ /*overrides*/
+}
+
+#toastr-container * {
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+#toastr-container > div {
+ position: relative;
+ pointer-events: auto;
+ overflow: hidden;
+ margin: 0 0 6px;
+ padding: 15px 15px 15px 50px;
+ width: 300px;
+ -moz-border-radius: 3px 3px 3px 3px;
+ -webkit-border-radius: 3px 3px 3px 3px;
+ border-radius: 3px 3px 3px 3px;
+ background-position: 15px center;
+ background-repeat: no-repeat;
+ -moz-box-shadow: 0 0 12px #999999;
+ -webkit-box-shadow: 0 0 12px #999999;
+ box-shadow: 0 0 12px #999999;
+ color: #FFFFFF;
+ opacity: 0.8;
+ -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
+ filter: alpha(opacity=80);
+}
+
+#toastr-container > div.rtl {
+ direction: rtl;
+ padding: 15px 50px 15px 15px;
+ background-position: right 15px center;
+}
+
+#toastr-container > div:hover {
+ -moz-box-shadow: 0 0 12px #000000;
+ -webkit-box-shadow: 0 0 12px #000000;
+ box-shadow: 0 0 12px #000000;
+ opacity: 1;
+ -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
+ filter: alpha(opacity=100);
+ cursor: pointer;
+}
+
+#toastr-container > .toastr-info {
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=") !important;
+}
+
+#toastr-container > .toastr-error {
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=") !important;
+}
+
+#toastr-container > .toastr-success {
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==") !important;
+}
+
+#toastr-container > .toastr-warning {
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=") !important;
+}
+
+#toastr-container.toastr-top-center-nav-margin > div,
+#toastr-container.toastr-top-center > div,
+#toastr-container.toastr-bottom-center > div {
+ width: 300px;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+#toastr-container.toastr-top-full-width-nav-margin > div,
+#toastr-container.toastr-top-full-width > div,
+#toastr-container.toastr-bottom-full-width > div {
+ width: 96%;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.toastr {
+ background-color: #030303;
+}
+
+.toastr-success {
+ background-color: #51A351;
+}
+
+.toastr-error {
+ background-color: #BD362F;
+}
+
+.toastr-info {
+ background-color: #2F96B4;
+}
+
+.toastr-warning {
+ background-color: #F89406;
+}
+
+.toastr-progress {
+ position: absolute;
+ left: 0;
+ bottom: 0;
+ height: 4px;
+ background-color: #000000;
+ opacity: 0.4;
+ -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40);
+ filter: alpha(opacity=40);
+}
+
+/*Responsive Design*/
+@media all and (max-width: 240px) {
+ #toastr-container > div {
+ padding: 8px 8px 8px 50px;
+ width: 11em;
+ }
+ #toastr-container > div.rtl {
+ padding: 8px 50px 8px 8px;
+ }
+ #toastr-container .toastr-close-button {
+ right: -0.2em;
+ top: -0.2em;
+ }
+ #toastr-container .rtl .toastr-close-button {
+ left: -0.2em;
+ right: 0.2em;
+ }
+}
+@media all and (min-width: 241px) and (max-width: 480px) {
+ #toastr-container > div {
+ padding: 8px 8px 8px 50px;
+ width: 18em;
+ }
+ #toastr-container > div.rtl {
+ padding: 8px 50px 8px 8px;
+ }
+ #toastr-container .toastr-close-button {
+ right: -0.2em;
+ top: -0.2em;
+ }
+ #toastr-container .rtl .toastr-close-button {
+ left: -0.2em;
+ right: 0.2em;
+ }
+}
+@media all and (min-width: 481px) and (max-width: 768px) {
+ #toastr-container > div {
+ padding: 15px 15px 15px 50px;
+ width: 25em;
+ }
+ #toastr-container > div.rtl {
+ padding: 15px 50px 15px 15px;
+ }
+}
+
+.toastr {
+ background-position: 1.5rem center /*rtl:calc(100% - 1.5rem) center*/ !important;
+ box-shadow: var(--kt-dropdown-box-shadow) !important;
+ border-radius: 0.475rem !important;
+ border: 0 !important;
+ background-color: var(--kt-gray-100);
+ color: var(--kt-gray-700);
+ padding: 1.25rem 1.25rem 1.25rem 4.5rem !important;
+}
+.toastr .toastr-close-button {
+ outline: none !important;
+ font-size: 0;
+ width: 0.85rem;
+ height: 0.85rem;
+}
+.toastr .toastr-title {
+ font-size: 1.15rem;
+ font-weight: 500;
+}
+.toastr .toastr-title + .toastr-message {
+ margin-top: 0.25rem;
+}
+.toastr .toastr-message {
+ font-size: 1rem;
+ font-weight: 400;
+}
+.toastr.toastr-success {
+ background-color: var(--kt-success);
+ color: var(--kt-success-inverse);
+}
+.toastr.toastr-success .toastr-close-button {
+ mask-repeat: no-repeat;
+ mask-position: center;
+ -webkit-mask-repeat: no-repeat;
+ -webkit-mask-position: center;
+ background-color: var(--kt-success-inverse);
+ -webkit-mask-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='var%28--kt-success-inverse%29'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e");
+ mask-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='var%28--kt-success-inverse%29'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e");
+}
+.toastr.toastr-info {
+ background-color: var(--kt-info);
+ color: var(--kt-info-inverse);
+}
+.toastr.toastr-info .toastr-close-button {
+ mask-repeat: no-repeat;
+ mask-position: center;
+ -webkit-mask-repeat: no-repeat;
+ -webkit-mask-position: center;
+ background-color: var(--kt-info-inverse);
+ -webkit-mask-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='var%28--kt-info-inverse%29'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e");
+ mask-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='var%28--kt-info-inverse%29'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e");
+}
+.toastr.toastr-warning {
+ background-color: var(--kt-warning);
+ color: var(--kt-warning-inverse);
+}
+.toastr.toastr-warning .toastr-close-button {
+ mask-repeat: no-repeat;
+ mask-position: center;
+ -webkit-mask-repeat: no-repeat;
+ -webkit-mask-position: center;
+ background-color: var(--kt-warning-inverse);
+ -webkit-mask-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='var%28--kt-warning-inverse%29'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e");
+ mask-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='var%28--kt-warning-inverse%29'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e");
+}
+.toastr.toastr-error {
+ background-color: var(--kt-danger);
+ color: var(--kt-danger-inverse);
+}
+.toastr.toastr-error .toastr-close-button {
+ mask-repeat: no-repeat;
+ mask-position: center;
+ -webkit-mask-repeat: no-repeat;
+ -webkit-mask-position: center;
+ background-color: var(--kt-danger-inverse);
+ -webkit-mask-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='var%28--kt-danger-inverse%29'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e");
+ mask-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='var%28--kt-danger-inverse%29'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e");
+}
+
+.toastr-top-center {
+ top: 12px;
+}
+
+.toastr-bottom-center {
+ bottom: 12px;
+}
\ No newline at end of file
diff --git a/Moonlight/wwwroot/assets/js/bootstrap.min.js b/Moonlight/wwwroot/assets/js/bootstrap.min.js
new file mode 100644
index 00000000..f2a11d15
--- /dev/null
+++ b/Moonlight/wwwroot/assets/js/bootstrap.min.js
@@ -0,0 +1,7 @@
+/*!
+ * Bootstrap v5.3.1 (https://getbootstrap.com/)
+ * Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ */
+!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e(t.Popper)}(this,(function(t){"use strict";function e(t){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t)for(const i in t)if("default"!==i){const s=Object.getOwnPropertyDescriptor(t,i);Object.defineProperty(e,i,s.get?s:{enumerable:!0,get:()=>t[i]})}return e.default=t,Object.freeze(e)}const i=e(t),s=new Map,n={set(t,e,i){s.has(t)||s.set(t,new Map);const n=s.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>s.has(t)&&s.get(t).get(e)||null,remove(t,e){if(!s.has(t))return;const i=s.get(t);i.delete(e),0===i.size&&s.delete(t)}},o="transitionend",r=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),a=t=>{t.dispatchEvent(new Event(o))},l=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),c=t=>l(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(r(t)):null,h=t=>{if(!l(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},d=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),u=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?u(t.parentNode):null},_=()=>{},g=t=>{t.offsetHeight},f=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,m=[],p=()=>"rtl"===document.documentElement.dir,b=t=>{var e;e=()=>{const e=f();if(e){const i=t.NAME,s=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=s,t.jQueryInterface)}},"loading"===document.readyState?(m.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of m)t()})),m.push(e)):e()},v=(t,e=[],i=t)=>"function"==typeof t?t(...e):i,y=(t,e,i=!0)=>{if(!i)return void v(t);const s=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const s=Number.parseFloat(e),n=Number.parseFloat(i);return s||n?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let n=!1;const r=({target:i})=>{i===e&&(n=!0,e.removeEventListener(o,r),v(t))};e.addEventListener(o,r),setTimeout((()=>{n||a(e)}),s)},w=(t,e,i,s)=>{const n=t.length;let o=t.indexOf(e);return-1===o?!i&&s?t[n-1]:t[0]:(o+=i?1:-1,s&&(o=(o+n)%n),t[Math.max(0,Math.min(o,n-1))])},A=/[^.]*(?=\..*)\.|.*/,E=/\..*/,C=/::\d+$/,T={};let k=1;const $={mouseenter:"mouseover",mouseleave:"mouseout"},S=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function L(t,e){return e&&`${e}::${k++}`||t.uidEvent||k++}function O(t){const e=L(t);return t.uidEvent=e,T[e]=T[e]||{},T[e]}function I(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function D(t,e,i){const s="string"==typeof e,n=s?i:e||i;let o=M(t);return S.has(o)||(o=t),[s,n,o]}function N(t,e,i,s,n){if("string"!=typeof e||!t)return;let[o,r,a]=D(e,i,s);if(e in $){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=O(t),c=l[a]||(l[a]={}),h=I(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&n);const d=L(r,e.replace(A,"")),u=o?function(t,e,i){return function s(n){const o=t.querySelectorAll(e);for(let{target:r}=n;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return F(n,{delegateTarget:r}),s.oneOff&&j.off(t,n.type,e,i),i.apply(r,[n])}}(t,i,r):function(t,e){return function i(s){return F(s,{delegateTarget:t}),i.oneOff&&j.off(t,s.type,e),e.apply(t,[s])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=n,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function P(t,e,i,s,n){const o=I(e[i],s,n);o&&(t.removeEventListener(i,o,Boolean(n)),delete e[i][o.uidEvent])}function x(t,e,i,s){const n=e[i]||{};for(const[o,r]of Object.entries(n))o.includes(s)&&P(t,e,i,r.callable,r.delegationSelector)}function M(t){return t=t.replace(E,""),$[t]||t}const j={on(t,e,i,s){N(t,e,i,s,!1)},one(t,e,i,s){N(t,e,i,s,!0)},off(t,e,i,s){if("string"!=typeof e||!t)return;const[n,o,r]=D(e,i,s),a=r!==e,l=O(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))x(t,l,i,e.slice(1));for(const[i,s]of Object.entries(c)){const n=i.replace(C,"");a&&!e.includes(n)||P(t,l,r,s.callable,s.delegationSelector)}}else{if(!Object.keys(c).length)return;P(t,l,r,o,n?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const s=f();let n=null,o=!0,r=!0,a=!1;e!==M(e)&&s&&(n=s.Event(e,i),s(t).trigger(n),o=!n.isPropagationStopped(),r=!n.isImmediatePropagationStopped(),a=n.isDefaultPrevented());const l=F(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&n&&n.preventDefault(),l}};function F(t,e={}){for(const[i,s]of Object.entries(e))try{t[i]=s}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>s})}return t}function z(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function H(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const B={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${H(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${H(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter((t=>t.startsWith("bs")&&!t.startsWith("bsConfig")));for(const s of i){let i=s.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1,i.length),e[i]=z(t.dataset[s])}return e},getDataAttribute:(t,e)=>z(t.getAttribute(`data-bs-${H(e)}`))};class q{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=l(e)?B.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...l(e)?B.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[s,n]of Object.entries(e)){const e=t[s],o=l(e)?"element":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(n).test(o))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${s}" provided type "${o}" but expected type "${n}".`)}var i}}class W extends q{constructor(t,e){super(),(t=c(t))&&(this._element=t,this._config=this._getConfig(e),n.set(this._element,this.constructor.DATA_KEY,this))}dispose(){n.remove(this._element,this.constructor.DATA_KEY),j.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){y(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return n.get(c(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.1"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const R=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return r(e)},K={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let s=t.parentNode.closest(e);for(;s;)i.push(s),s=s.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(",");return this.find(e,t).filter((t=>!d(t)&&h(t)))},getSelectorFromElement(t){const e=R(t);return e&&K.findOne(e)?e:null},getElementFromSelector(t){const e=R(t);return e?K.findOne(e):null},getMultipleElementsFromSelector(t){const e=R(t);return e?K.find(e):[]}},V=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,s=t.NAME;j.on(document,i,`[data-bs-dismiss="${s}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),d(this))return;const n=K.getElementFromSelector(this)||this.closest(`.${s}`);t.getOrCreateInstance(n)[e]()}))},Q=".bs.alert",X=`close${Q}`,Y=`closed${Q}`;class U extends W{static get NAME(){return"alert"}close(){if(j.trigger(this._element,X).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),j.trigger(this._element,Y),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=U.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}V(U,"close"),b(U);const G='[data-bs-toggle="button"]';class J extends W{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=J.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}j.on(document,"click.bs.button.data-api",G,(t=>{t.preventDefault();const e=t.target.closest(G);J.getOrCreateInstance(e).toggle()})),b(J);const Z=".bs.swipe",tt=`touchstart${Z}`,et=`touchmove${Z}`,it=`touchend${Z}`,st=`pointerdown${Z}`,nt=`pointerup${Z}`,ot={endCallback:null,leftCallback:null,rightCallback:null},rt={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class at extends q{constructor(t,e){super(),this._element=t,t&&at.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return ot}static get DefaultType(){return rt}static get NAME(){return"swipe"}dispose(){j.off(this._element,Z)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),v(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&v(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(j.on(this._element,st,(t=>this._start(t))),j.on(this._element,nt,(t=>this._end(t))),this._element.classList.add("pointer-event")):(j.on(this._element,tt,(t=>this._start(t))),j.on(this._element,et,(t=>this._move(t))),j.on(this._element,it,(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const lt=".bs.carousel",ct=".data-api",ht="next",dt="prev",ut="left",_t="right",gt=`slide${lt}`,ft=`slid${lt}`,mt=`keydown${lt}`,pt=`mouseenter${lt}`,bt=`mouseleave${lt}`,vt=`dragstart${lt}`,yt=`load${lt}${ct}`,wt=`click${lt}${ct}`,At="carousel",Et="active",Ct=".active",Tt=".carousel-item",kt=Ct+Tt,$t={ArrowLeft:_t,ArrowRight:ut},St={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},Lt={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class Ot extends W{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=K.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===At&&this.cycle()}static get Default(){return St}static get DefaultType(){return Lt}static get NAME(){return"carousel"}next(){this._slide(ht)}nextWhenVisible(){!document.hidden&&h(this._element)&&this.next()}prev(){this._slide(dt)}pause(){this._isSliding&&a(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?j.one(this._element,ft,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void j.one(this._element,ft,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const s=t>i?ht:dt;this._slide(s,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&j.on(this._element,mt,(t=>this._keydown(t))),"hover"===this._config.pause&&(j.on(this._element,pt,(()=>this.pause())),j.on(this._element,bt,(()=>this._maybeEnableCycle()))),this._config.touch&&at.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of K.find(".carousel-item img",this._element))j.on(t,vt,(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(ut)),rightCallback:()=>this._slide(this._directionToOrder(_t)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new at(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=$t[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=K.findOne(Ct,this._indicatorsElement);e.classList.remove(Et),e.removeAttribute("aria-current");const i=K.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(Et),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),s=t===ht,n=e||w(this._getItems(),i,s,this._config.wrap);if(n===i)return;const o=this._getItemIndex(n),r=e=>j.trigger(this._element,e,{relatedTarget:n,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(gt).defaultPrevented)return;if(!i||!n)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=n;const l=s?"carousel-item-start":"carousel-item-end",c=s?"carousel-item-next":"carousel-item-prev";n.classList.add(c),g(n),i.classList.add(l),n.classList.add(l),this._queueCallback((()=>{n.classList.remove(l,c),n.classList.add(Et),i.classList.remove(Et,c,l),this._isSliding=!1,r(ft)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return K.findOne(kt,this._element)}_getItems(){return K.find(Tt,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return p()?t===ut?dt:ht:t===ut?ht:dt}_orderToDirection(t){return p()?t===dt?ut:_t:t===dt?_t:ut}static jQueryInterface(t){return this.each((function(){const e=Ot.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)}))}}j.on(document,wt,"[data-bs-slide], [data-bs-slide-to]",(function(t){const e=K.getElementFromSelector(this);if(!e||!e.classList.contains(At))return;t.preventDefault();const i=Ot.getOrCreateInstance(e),s=this.getAttribute("data-bs-slide-to");return s?(i.to(s),void i._maybeEnableCycle()):"next"===B.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),j.on(window,yt,(()=>{const t=K.find('[data-bs-ride="carousel"]');for(const e of t)Ot.getOrCreateInstance(e)})),b(Ot);const It=".bs.collapse",Dt=`show${It}`,Nt=`shown${It}`,Pt=`hide${It}`,xt=`hidden${It}`,Mt=`click${It}.data-api`,jt="show",Ft="collapse",zt="collapsing",Ht=`:scope .${Ft} .${Ft}`,Bt='[data-bs-toggle="collapse"]',qt={parent:null,toggle:!0},Wt={parent:"(null|element)",toggle:"boolean"};class Rt extends W{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=K.find(Bt);for(const t of i){const e=K.getSelectorFromElement(t),i=K.find(e).filter((t=>t===this._element));null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return qt}static get DefaultType(){return Wt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter((t=>t!==this._element)).map((t=>Rt.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(j.trigger(this._element,Dt).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Ft),this._element.classList.add(zt),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(zt),this._element.classList.add(Ft,jt),this._element.style[e]="",j.trigger(this._element,Nt)}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(j.trigger(this._element,Pt).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,g(this._element),this._element.classList.add(zt),this._element.classList.remove(Ft,jt);for(const t of this._triggerArray){const e=K.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(zt),this._element.classList.add(Ft),j.trigger(this._element,xt)}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(jt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=c(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Bt);for(const e of t){const t=K.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=K.find(Ht,this._config.parent);return K.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const i=Rt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}j.on(document,Mt,Bt,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of K.getMultipleElementsFromSelector(this))Rt.getOrCreateInstance(t,{toggle:!1}).toggle()})),b(Rt);const Kt="dropdown",Vt=".bs.dropdown",Qt=".data-api",Xt="ArrowUp",Yt="ArrowDown",Ut=`hide${Vt}`,Gt=`hidden${Vt}`,Jt=`show${Vt}`,Zt=`shown${Vt}`,te=`click${Vt}${Qt}`,ee=`keydown${Vt}${Qt}`,ie=`keyup${Vt}${Qt}`,se="show",ne='[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)',oe=`${ne}.${se}`,re=".dropdown-menu",ae=p()?"top-end":"top-start",le=p()?"top-start":"top-end",ce=p()?"bottom-end":"bottom-start",he=p()?"bottom-start":"bottom-end",de=p()?"left-start":"right-start",ue=p()?"right-start":"left-start",_e={autoClose:!0,boundary:"clippingParents",display:"dynamic",offset:[0,2],popperConfig:null,reference:"toggle"},ge={autoClose:"(boolean|string)",boundary:"(string|element)",display:"string",offset:"(array|string|function)",popperConfig:"(null|object|function)",reference:"(string|element|object)"};class fe extends W{constructor(t,e){super(t,e),this._popper=null,this._parent=this._element.parentNode,this._menu=K.next(this._element,re)[0]||K.prev(this._element,re)[0]||K.findOne(re,this._parent),this._inNavbar=this._detectNavbar()}static get Default(){return _e}static get DefaultType(){return ge}static get NAME(){return Kt}toggle(){return this._isShown()?this.hide():this.show()}show(){if(d(this._element)||this._isShown())return;const t={relatedTarget:this._element};if(!j.trigger(this._element,Jt,t).defaultPrevented){if(this._createPopper(),"ontouchstart"in document.documentElement&&!this._parent.closest(".navbar-nav"))for(const t of[].concat(...document.body.children))j.on(t,"mouseover",_);this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(se),this._element.classList.add(se),j.trigger(this._element,Zt,t)}}hide(){if(d(this._element)||!this._isShown())return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){if(!j.trigger(this._element,Ut,t).defaultPrevented){if("ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))j.off(t,"mouseover",_);this._popper&&this._popper.destroy(),this._menu.classList.remove(se),this._element.classList.remove(se),this._element.setAttribute("aria-expanded","false"),B.removeDataAttribute(this._menu,"popper"),j.trigger(this._element,Gt,t)}}_getConfig(t){if("object"==typeof(t=super._getConfig(t)).reference&&!l(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Kt.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(){if(void 0===i)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let t=this._element;"parent"===this._config.reference?t=this._parent:l(this._config.reference)?t=c(this._config.reference):"object"==typeof this._config.reference&&(t=this._config.reference);const e=this._getPopperConfig();this._popper=i.createPopper(t,this._menu,e)}_isShown(){return this._menu.classList.contains(se)}_getPlacement(){const t=this._parent;if(t.classList.contains("dropend"))return de;if(t.classList.contains("dropstart"))return ue;if(t.classList.contains("dropup-center"))return"top";if(t.classList.contains("dropdown-center"))return"bottom";const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?le:ae:e?he:ce}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(B.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...v(this._config.popperConfig,[t])}}_selectMenuItem({key:t,target:e}){const i=K.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>h(t)));i.length&&w(i,e,t===Yt,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=fe.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=K.find(oe);for(const i of e){const e=fe.getInstance(i);if(!e||!1===e._config.autoClose)continue;const s=t.composedPath(),n=s.includes(e._menu);if(s.includes(e._element)||"inside"===e._config.autoClose&&!n||"outside"===e._config.autoClose&&n)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,s=[Xt,Yt].includes(t.key);if(!s&&!i)return;if(e&&!i)return;t.preventDefault();const n=this.matches(ne)?this:K.prev(this,ne)[0]||K.next(this,ne)[0]||K.findOne(ne,t.delegateTarget.parentNode),o=fe.getOrCreateInstance(n);if(s)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),n.focus())}}j.on(document,ee,ne,fe.dataApiKeydownHandler),j.on(document,ee,re,fe.dataApiKeydownHandler),j.on(document,te,fe.clearMenus),j.on(document,ie,fe.clearMenus),j.on(document,te,ne,(function(t){t.preventDefault(),fe.getOrCreateInstance(this).toggle()})),b(fe);const me="backdrop",pe="show",be=`mousedown.bs.${me}`,ve={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},ye={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class we extends q{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return ve}static get DefaultType(){return ye}static get NAME(){return me}show(t){if(!this._config.isVisible)return void v(t);this._append();const e=this._getElement();this._config.isAnimated&&g(e),e.classList.add(pe),this._emulateAnimation((()=>{v(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(pe),this._emulateAnimation((()=>{this.dispose(),v(t)}))):v(t)}dispose(){this._isAppended&&(j.off(this._element,be),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=c(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),j.on(t,be,(()=>{v(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){y(t,this._getElement(),this._config.isAnimated)}}const Ae=".bs.focustrap",Ee=`focusin${Ae}`,Ce=`keydown.tab${Ae}`,Te="backward",ke={autofocus:!0,trapElement:null},$e={autofocus:"boolean",trapElement:"element"};class Se extends q{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return ke}static get DefaultType(){return $e}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),j.off(document,Ae),j.on(document,Ee,(t=>this._handleFocusin(t))),j.on(document,Ce,(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,j.off(document,Ae))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=K.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===Te?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?Te:"forward")}}const Le=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",Oe=".sticky-top",Ie="padding-right",De="margin-right";class Ne{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,Ie,(e=>e+t)),this._setElementAttributes(Le,Ie,(e=>e+t)),this._setElementAttributes(Oe,De,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,Ie),this._resetElementAttributes(Le,Ie),this._resetElementAttributes(Oe,De)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const s=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+s)return;this._saveInitialAttribute(t,e);const n=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(n))}px`)}))}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&B.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=B.getDataAttribute(t,e);null!==i?(B.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(l(t))e(t);else for(const i of K.find(t,this._element))e(i)}}const Pe=".bs.modal",xe=`hide${Pe}`,Me=`hidePrevented${Pe}`,je=`hidden${Pe}`,Fe=`show${Pe}`,ze=`shown${Pe}`,He=`resize${Pe}`,Be=`click.dismiss${Pe}`,qe=`mousedown.dismiss${Pe}`,We=`keydown.dismiss${Pe}`,Re=`click${Pe}.data-api`,Ke="modal-open",Ve="show",Qe="modal-static",Xe={backdrop:!0,focus:!0,keyboard:!0},Ye={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class Ue extends W{constructor(t,e){super(t,e),this._dialog=K.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new Ne,this._addEventListeners()}static get Default(){return Xe}static get DefaultType(){return Ye}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||j.trigger(this._element,Fe,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(Ke),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(j.trigger(this._element,xe).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(Ve),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){j.off(window,Pe),j.off(this._dialog,Pe),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new we({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Se({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=K.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),g(this._element),this._element.classList.add(Ve),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,j.trigger(this._element,ze,{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){j.on(this._element,We,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),j.on(window,He,(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),j.on(this._element,qe,(t=>{j.one(this._element,Be,(e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}))}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(Ke),this._resetAdjustments(),this._scrollBar.reset(),j.trigger(this._element,je)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(j.trigger(this._element,Me).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(Qe)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(Qe),this._queueCallback((()=>{this._element.classList.remove(Qe),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=p()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=p()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=Ue.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}j.on(document,Re,'[data-bs-toggle="modal"]',(function(t){const e=K.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),j.one(e,Fe,(t=>{t.defaultPrevented||j.one(e,je,(()=>{h(this)&&this.focus()}))}));const i=K.findOne(".modal.show");i&&Ue.getInstance(i).hide(),Ue.getOrCreateInstance(e).toggle(this)})),V(Ue),b(Ue);const Ge=".bs.offcanvas",Je=".data-api",Ze=`load${Ge}${Je}`,ti="show",ei="showing",ii="hiding",si=".offcanvas.show",ni=`show${Ge}`,oi=`shown${Ge}`,ri=`hide${Ge}`,ai=`hidePrevented${Ge}`,li=`hidden${Ge}`,ci=`resize${Ge}`,hi=`click${Ge}${Je}`,di=`keydown.dismiss${Ge}`,ui={backdrop:!0,keyboard:!0,scroll:!1},_i={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class gi extends W{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return ui}static get DefaultType(){return _i}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||j.trigger(this._element,ni,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new Ne).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(ei),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(ti),this._element.classList.remove(ei),j.trigger(this._element,oi,{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(j.trigger(this._element,ri).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add(ii),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove(ti,ii),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new Ne).reset(),j.trigger(this._element,li)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new we({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():j.trigger(this._element,ai)}:null})}_initializeFocusTrap(){return new Se({trapElement:this._element})}_addEventListeners(){j.on(this._element,di,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():j.trigger(this._element,ai))}))}static jQueryInterface(t){return this.each((function(){const e=gi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}j.on(document,hi,'[data-bs-toggle="offcanvas"]',(function(t){const e=K.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),d(this))return;j.one(e,li,(()=>{h(this)&&this.focus()}));const i=K.findOne(si);i&&i!==e&&gi.getInstance(i).hide(),gi.getOrCreateInstance(e).toggle(this)})),j.on(window,Ze,(()=>{for(const t of K.find(si))gi.getOrCreateInstance(t).show()})),j.on(window,ci,(()=>{for(const t of K.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&gi.getOrCreateInstance(t).hide()})),V(gi),b(gi);const fi={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},mi=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),pi=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,bi=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!mi.has(i)||Boolean(pi.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},vi={allowList:fi,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"
"},yi={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},wi={entry:"(string|element|function|null)",selector:"(string|element)"};class Ai extends q{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return vi}static get DefaultType(){return yi}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},wi)}_setContent(t,e,i){const s=K.findOne(i,t);s&&((e=this._resolvePossibleFunction(e))?l(e)?this._putElementInTemplate(c(e),s):this._config.html?s.innerHTML=this._maybeSanitize(e):s.textContent=e:s.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const s=(new window.DOMParser).parseFromString(t,"text/html"),n=[].concat(...s.body.querySelectorAll("*"));for(const t of n){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const s=[].concat(...t.attributes),n=[].concat(e["*"]||[],e[i]||[]);for(const e of s)bi(e,n)||t.removeAttribute(e.nodeName)}return s.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return v(t,[this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const Ei=new Set(["sanitize","allowList","sanitizeFn"]),Ci="fade",Ti="show",ki=".modal",$i="hide.bs.modal",Si="hover",Li="focus",Oi={AUTO:"auto",TOP:"top",RIGHT:p()?"left":"right",BOTTOM:"bottom",LEFT:p()?"right":"left"},Ii={allowList:fi,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'',title:"",trigger:"hover focus"},Di={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class Ni extends W{constructor(t,e){if(void 0===i)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return Ii}static get DefaultType(){return Di}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._activeTrigger.click=!this._activeTrigger.click,this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),j.off(this._element.closest(ki),$i,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=j.trigger(this._element,this.constructor.eventName("show")),e=(u(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:s}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(s.append(i),j.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(Ti),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))j.on(t,"mouseover",_);this._queueCallback((()=>{j.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(this._isShown()&&!j.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(Ti),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))j.off(t,"mouseover",_);this._activeTrigger.click=!1,this._activeTrigger[Li]=!1,this._activeTrigger[Si]=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),j.trigger(this._element,this.constructor.eventName("hidden")))}),this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(Ci,Ti),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(Ci),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new Ai({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{".tooltip-inner":this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(Ci)}_isShown(){return this.tip&&this.tip.classList.contains(Ti)}_createPopper(t){const e=v(this._config.placement,[this,t,this._element]),s=Oi[e.toUpperCase()];return i.createPopper(this._element,t,this._getPopperConfig(s))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return v(t,[this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...v(this._config.popperConfig,[e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)j.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>{this._initializeOnDelegatedTarget(t).toggle()}));else if("manual"!==e){const t=e===Si?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===Si?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");j.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?Li:Si]=!0,e._enter()})),j.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?Li:Si]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},j.on(this._element.closest(ki),$i,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=B.getDataAttributes(this._element);for(const t of Object.keys(e))Ei.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:c(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each((function(){const e=Ni.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}b(Ni);const Pi={...Ni.Default,content:"",offset:[0,8],placement:"right",template:'',trigger:"click"},xi={...Ni.DefaultType,content:"(null|string|element|function)"};class Mi extends Ni{static get Default(){return Pi}static get DefaultType(){return xi}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{".popover-header":this._getTitle(),".popover-body":this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=Mi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}b(Mi);const ji=".bs.scrollspy",Fi=`activate${ji}`,zi=`click${ji}`,Hi=`load${ji}.data-api`,Bi="active",qi="[href]",Wi=".nav-link",Ri=`${Wi}, .nav-item > ${Wi}, .list-group-item`,Ki={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},Vi={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class Qi extends W{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return Ki}static get DefaultType(){return Vi}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=c(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map((t=>Number.parseFloat(t)))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(j.off(this._config.target,zi),j.on(this._config.target,zi,qi,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,s=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:s,behavior:"smooth"});i.scrollTop=s}})))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},s=(this._rootElement||document.documentElement).scrollTop,n=s>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=s;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(n&&t){if(i(o),!s)return}else n||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=K.find(qi,this._config.target);for(const e of t){if(!e.hash||d(e))continue;const t=K.findOne(decodeURI(e.hash),this._element);h(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(Bi),this._activateParents(t),j.trigger(this._element,Fi,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))K.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(Bi);else for(const e of K.parents(t,".nav, .list-group"))for(const t of K.prev(e,Ri))t.classList.add(Bi)}_clearActiveClass(t){t.classList.remove(Bi);const e=K.find(`${qi}.${Bi}`,t);for(const t of e)t.classList.remove(Bi)}static jQueryInterface(t){return this.each((function(){const e=Qi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(window,Hi,(()=>{for(const t of K.find('[data-bs-spy="scroll"]'))Qi.getOrCreateInstance(t)})),b(Qi);const Xi=".bs.tab",Yi=`hide${Xi}`,Ui=`hidden${Xi}`,Gi=`show${Xi}`,Ji=`shown${Xi}`,Zi=`click${Xi}`,ts=`keydown${Xi}`,es=`load${Xi}`,is="ArrowLeft",ss="ArrowRight",ns="ArrowUp",os="ArrowDown",rs="Home",as="End",ls="active",cs="fade",hs="show",ds=":not(.dropdown-toggle)",us='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',_s=`.nav-link${ds}, .list-group-item${ds}, [role="tab"]${ds}, ${us}`,gs=`.${ls}[data-bs-toggle="tab"], .${ls}[data-bs-toggle="pill"], .${ls}[data-bs-toggle="list"]`;class fs extends W{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),j.on(this._element,ts,(t=>this._keydown(t))))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?j.trigger(e,Yi,{relatedTarget:t}):null;j.trigger(t,Gi,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(ls),this._activate(K.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),j.trigger(t,Ji,{relatedTarget:e})):t.classList.add(hs)}),t,t.classList.contains(cs)))}_deactivate(t,e){t&&(t.classList.remove(ls),t.blur(),this._deactivate(K.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),j.trigger(t,Ui,{relatedTarget:e})):t.classList.remove(hs)}),t,t.classList.contains(cs)))}_keydown(t){if(![is,ss,ns,os,rs,as].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!d(t)));let i;if([rs,as].includes(t.key))i=e[t.key===rs?0:e.length-1];else{const s=[ss,os].includes(t.key);i=w(e,t.target,s,!0)}i&&(i.focus({preventScroll:!0}),fs.getOrCreateInstance(i).show())}_getChildren(){return K.find(_s,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=K.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const s=(t,s)=>{const n=K.findOne(t,i);n&&n.classList.toggle(s,e)};s(".dropdown-toggle",ls),s(".dropdown-menu",hs),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(ls)}_getInnerElement(t){return t.matches(_s)?t:K.findOne(_s,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=fs.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(document,Zi,us,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),d(this)||fs.getOrCreateInstance(this).show()})),j.on(window,es,(()=>{for(const t of K.find(gs))fs.getOrCreateInstance(t)})),b(fs);const ms=".bs.toast",ps=`mouseover${ms}`,bs=`mouseout${ms}`,vs=`focusin${ms}`,ys=`focusout${ms}`,ws=`hide${ms}`,As=`hidden${ms}`,Es=`show${ms}`,Cs=`shown${ms}`,Ts="hide",ks="show",$s="showing",Ss={animation:"boolean",autohide:"boolean",delay:"number"},Ls={animation:!0,autohide:!0,delay:5e3};class Os extends W{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return Ls}static get DefaultType(){return Ss}static get NAME(){return"toast"}show(){j.trigger(this._element,Es).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(Ts),g(this._element),this._element.classList.add(ks,$s),this._queueCallback((()=>{this._element.classList.remove($s),j.trigger(this._element,Cs),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(j.trigger(this._element,ws).defaultPrevented||(this._element.classList.add($s),this._queueCallback((()=>{this._element.classList.add(Ts),this._element.classList.remove($s,ks),j.trigger(this._element,As)}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(ks),super.dispose()}isShown(){return this._element.classList.contains(ks)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){j.on(this._element,ps,(t=>this._onInteraction(t,!0))),j.on(this._element,bs,(t=>this._onInteraction(t,!1))),j.on(this._element,vs,(t=>this._onInteraction(t,!0))),j.on(this._element,ys,(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=Os.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return V(Os),b(Os),{Alert:U,Button:J,Carousel:Ot,Collapse:Rt,Dropdown:fe,Modal:Ue,Offcanvas:gi,Popover:Mi,ScrollSpy:Qi,Tab:fs,Toast:Os,Tooltip:Ni}}));
+//# sourceMappingURL=bootstrap.min.js.map
\ No newline at end of file
diff --git a/Moonlight/wwwroot/assets/js/draggable.bundle.js b/Moonlight/wwwroot/assets/js/draggable.bundle.js
new file mode 100644
index 00000000..efc5ce0c
--- /dev/null
+++ b/Moonlight/wwwroot/assets/js/draggable.bundle.js
@@ -0,0 +1,7522 @@
+(function webpackUniversalModuleDefinition(root, factory) {
+ if(typeof exports === 'object' && typeof module === 'object')
+ module.exports = factory();
+ else if(typeof define === 'function' && define.amd)
+ define("Draggable", [], factory);
+ else if(typeof exports === 'object')
+ exports["Draggable"] = factory();
+ else
+ root["Draggable"] = factory();
+})(window, function() {
+return /******/ (function(modules) { // webpackBootstrap
+/******/ // The module cache
+/******/ var installedModules = {};
+/******/
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+/******/
+/******/ // Check if module is in cache
+/******/ if(installedModules[moduleId]) {
+/******/ return installedModules[moduleId].exports;
+/******/ }
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = installedModules[moduleId] = {
+/******/ i: moduleId,
+/******/ l: false,
+/******/ exports: {}
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+/******/
+/******/ // Flag the module as loaded
+/******/ module.l = true;
+/******/
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+/******/
+/******/
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = modules;
+/******/
+/******/ // expose the module cache
+/******/ __webpack_require__.c = installedModules;
+/******/
+/******/ // define getter function for harmony exports
+/******/ __webpack_require__.d = function(exports, name, getter) {
+/******/ if(!__webpack_require__.o(exports, name)) {
+/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
+/******/ }
+/******/ };
+/******/
+/******/ // define __esModule on exports
+/******/ __webpack_require__.r = function(exports) {
+/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
+/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
+/******/ }
+/******/ Object.defineProperty(exports, '__esModule', { value: true });
+/******/ };
+/******/
+/******/ // create a fake namespace object
+/******/ // mode & 1: value is a module id, require it
+/******/ // mode & 2: merge all properties of value into the ns
+/******/ // mode & 4: return value when already ns object
+/******/ // mode & 8|1: behave like require
+/******/ __webpack_require__.t = function(value, mode) {
+/******/ if(mode & 1) value = __webpack_require__(value);
+/******/ if(mode & 8) return value;
+/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
+/******/ var ns = Object.create(null);
+/******/ __webpack_require__.r(ns);
+/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
+/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
+/******/ return ns;
+/******/ };
+/******/
+/******/ // getDefaultExport function for compatibility with non-harmony modules
+/******/ __webpack_require__.n = function(module) {
+/******/ var getter = module && module.__esModule ?
+/******/ function getDefault() { return module['default']; } :
+/******/ function getModuleExports() { return module; };
+/******/ __webpack_require__.d(getter, 'a', getter);
+/******/ return getter;
+/******/ };
+/******/
+/******/ // Object.prototype.hasOwnProperty.call
+/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
+/******/
+/******/ // __webpack_public_path__
+/******/ __webpack_require__.p = "";
+/******/
+/******/
+/******/ // Load entry module and return exports
+/******/ return __webpack_require__(__webpack_require__.s = 72);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _AbstractPlugin = __webpack_require__(66);
+
+var _AbstractPlugin2 = _interopRequireDefault(_AbstractPlugin);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _AbstractPlugin2.default;
+
+/***/ }),
+/* 1 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _AbstractEvent = __webpack_require__(70);
+
+var _AbstractEvent2 = _interopRequireDefault(_AbstractEvent);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _AbstractEvent2.default;
+
+/***/ }),
+/* 2 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _closest = __webpack_require__(57);
+
+Object.defineProperty(exports, 'closest', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_closest).default;
+ }
+});
+
+var _requestNextAnimationFrame = __webpack_require__(55);
+
+Object.defineProperty(exports, 'requestNextAnimationFrame', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_requestNextAnimationFrame).default;
+ }
+});
+
+var _distance = __webpack_require__(53);
+
+Object.defineProperty(exports, 'distance', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_distance).default;
+ }
+});
+
+var _touchCoords = __webpack_require__(51);
+
+Object.defineProperty(exports, 'touchCoords', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_touchCoords).default;
+ }
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/***/ }),
+/* 3 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _SensorEvent = __webpack_require__(46);
+
+Object.keys(_SensorEvent).forEach(function (key) {
+ if (key === "default" || key === "__esModule") return;
+ Object.defineProperty(exports, key, {
+ enumerable: true,
+ get: function () {
+ return _SensorEvent[key];
+ }
+ });
+});
+
+/***/ }),
+/* 4 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _Sensor = __webpack_require__(49);
+
+var _Sensor2 = _interopRequireDefault(_Sensor);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _Sensor2.default;
+
+/***/ }),
+/* 5 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _DragEvent = __webpack_require__(14);
+
+Object.keys(_DragEvent).forEach(function (key) {
+ if (key === "default" || key === "__esModule") return;
+ Object.defineProperty(exports, key, {
+ enumerable: true,
+ get: function () {
+ return _DragEvent[key];
+ }
+ });
+});
+
+var _DraggableEvent = __webpack_require__(13);
+
+Object.keys(_DraggableEvent).forEach(function (key) {
+ if (key === "default" || key === "__esModule") return;
+ Object.defineProperty(exports, key, {
+ enumerable: true,
+ get: function () {
+ return _DraggableEvent[key];
+ }
+ });
+});
+
+var _Plugins = __webpack_require__(12);
+
+Object.keys(_Plugins).forEach(function (key) {
+ if (key === "default" || key === "__esModule") return;
+ Object.defineProperty(exports, key, {
+ enumerable: true,
+ get: function () {
+ return _Plugins[key];
+ }
+ });
+});
+
+var _Sensors = __webpack_require__(6);
+
+Object.keys(_Sensors).forEach(function (key) {
+ if (key === "default" || key === "__esModule") return;
+ Object.defineProperty(exports, key, {
+ enumerable: true,
+ get: function () {
+ return _Sensors[key];
+ }
+ });
+});
+
+var _Draggable = __webpack_require__(39);
+
+var _Draggable2 = _interopRequireDefault(_Draggable);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _Draggable2.default;
+
+/***/ }),
+/* 6 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _Sensor = __webpack_require__(4);
+
+Object.defineProperty(exports, 'Sensor', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_Sensor).default;
+ }
+});
+
+var _MouseSensor = __webpack_require__(48);
+
+Object.defineProperty(exports, 'MouseSensor', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_MouseSensor).default;
+ }
+});
+
+var _TouchSensor = __webpack_require__(45);
+
+Object.defineProperty(exports, 'TouchSensor', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_TouchSensor).default;
+ }
+});
+
+var _DragSensor = __webpack_require__(43);
+
+Object.defineProperty(exports, 'DragSensor', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_DragSensor).default;
+ }
+});
+
+var _ForceTouchSensor = __webpack_require__(41);
+
+Object.defineProperty(exports, 'ForceTouchSensor', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_ForceTouchSensor).default;
+ }
+});
+
+var _SensorEvent = __webpack_require__(3);
+
+Object.keys(_SensorEvent).forEach(function (key) {
+ if (key === "default" || key === "__esModule") return;
+ Object.defineProperty(exports, key, {
+ enumerable: true,
+ get: function () {
+ return _SensorEvent[key];
+ }
+ });
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/***/ }),
+/* 7 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _SnappableEvent = __webpack_require__(20);
+
+Object.keys(_SnappableEvent).forEach(function (key) {
+ if (key === "default" || key === "__esModule") return;
+ Object.defineProperty(exports, key, {
+ enumerable: true,
+ get: function () {
+ return _SnappableEvent[key];
+ }
+ });
+});
+
+/***/ }),
+/* 8 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _CollidableEvent = __webpack_require__(25);
+
+Object.keys(_CollidableEvent).forEach(function (key) {
+ if (key === "default" || key === "__esModule") return;
+ Object.defineProperty(exports, key, {
+ enumerable: true,
+ get: function () {
+ return _CollidableEvent[key];
+ }
+ });
+});
+
+/***/ }),
+/* 9 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _SortableEvent = __webpack_require__(29);
+
+Object.keys(_SortableEvent).forEach(function (key) {
+ if (key === "default" || key === "__esModule") return;
+ Object.defineProperty(exports, key, {
+ enumerable: true,
+ get: function () {
+ return _SortableEvent[key];
+ }
+ });
+});
+
+/***/ }),
+/* 10 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _SwappableEvent = __webpack_require__(32);
+
+Object.keys(_SwappableEvent).forEach(function (key) {
+ if (key === "default" || key === "__esModule") return;
+ Object.defineProperty(exports, key, {
+ enumerable: true,
+ get: function () {
+ return _SwappableEvent[key];
+ }
+ });
+});
+
+/***/ }),
+/* 11 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _DroppableEvent = __webpack_require__(35);
+
+Object.keys(_DroppableEvent).forEach(function (key) {
+ if (key === "default" || key === "__esModule") return;
+ Object.defineProperty(exports, key, {
+ enumerable: true,
+ get: function () {
+ return _DroppableEvent[key];
+ }
+ });
+});
+
+/***/ }),
+/* 12 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _Announcement = __webpack_require__(68);
+
+Object.defineProperty(exports, 'Announcement', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_Announcement).default;
+ }
+});
+Object.defineProperty(exports, 'defaultAnnouncementOptions', {
+ enumerable: true,
+ get: function () {
+ return _Announcement.defaultOptions;
+ }
+});
+
+var _Focusable = __webpack_require__(65);
+
+Object.defineProperty(exports, 'Focusable', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_Focusable).default;
+ }
+});
+
+var _Mirror = __webpack_require__(63);
+
+Object.defineProperty(exports, 'Mirror', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_Mirror).default;
+ }
+});
+Object.defineProperty(exports, 'defaultMirrorOptions', {
+ enumerable: true,
+ get: function () {
+ return _Mirror.defaultOptions;
+ }
+});
+
+var _Scrollable = __webpack_require__(59);
+
+Object.defineProperty(exports, 'Scrollable', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_Scrollable).default;
+ }
+});
+Object.defineProperty(exports, 'defaultScrollableOptions', {
+ enumerable: true,
+ get: function () {
+ return _Scrollable.defaultOptions;
+ }
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/***/ }),
+/* 13 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _DraggableEvent = __webpack_require__(69);
+
+Object.keys(_DraggableEvent).forEach(function (key) {
+ if (key === "default" || key === "__esModule") return;
+ Object.defineProperty(exports, key, {
+ enumerable: true,
+ get: function () {
+ return _DraggableEvent[key];
+ }
+ });
+});
+
+/***/ }),
+/* 14 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _DragEvent = __webpack_require__(71);
+
+Object.keys(_DragEvent).forEach(function (key) {
+ if (key === "default" || key === "__esModule") return;
+ Object.defineProperty(exports, key, {
+ enumerable: true,
+ get: function () {
+ return _DragEvent[key];
+ }
+ });
+});
+
+/***/ }),
+/* 15 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.defaultOptions = undefined;
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _AbstractPlugin = __webpack_require__(0);
+
+var _AbstractPlugin2 = _interopRequireDefault(_AbstractPlugin);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+const onSortableSorted = Symbol('onSortableSorted');
+const onSortableSort = Symbol('onSortableSort');
+
+/**
+ * SortAnimation default options
+ * @property {Object} defaultOptions
+ * @property {Number} defaultOptions.duration
+ * @property {String} defaultOptions.easingFunction
+ * @type {Object}
+ */
+const defaultOptions = exports.defaultOptions = {
+ duration: 150,
+ easingFunction: 'ease-in-out'
+};
+
+/**
+ * SortAnimation plugin adds sort animation for sortable
+ * @class SortAnimation
+ * @module SortAnimation
+ * @extends AbstractPlugin
+ */
+class SortAnimation extends _AbstractPlugin2.default {
+ /**
+ * SortAnimation constructor.
+ * @constructs SortAnimation
+ * @param {Draggable} draggable - Draggable instance
+ */
+ constructor(draggable) {
+ super(draggable);
+
+ /**
+ * SortAnimation options
+ * @property {Object} options
+ * @property {Number} defaultOptions.duration
+ * @property {String} defaultOptions.easingFunction
+ * @type {Object}
+ */
+ this.options = _extends({}, defaultOptions, this.getOptions());
+
+ /**
+ * Last animation frame
+ * @property {Number} lastAnimationFrame
+ * @type {Number}
+ */
+ this.lastAnimationFrame = null;
+ this.lastElements = [];
+
+ this[onSortableSorted] = this[onSortableSorted].bind(this);
+ this[onSortableSort] = this[onSortableSort].bind(this);
+ }
+
+ /**
+ * Attaches plugins event listeners
+ */
+ attach() {
+ this.draggable.on('sortable:sort', this[onSortableSort]);
+ this.draggable.on('sortable:sorted', this[onSortableSorted]);
+ }
+
+ /**
+ * Detaches plugins event listeners
+ */
+ detach() {
+ this.draggable.off('sortable:sort', this[onSortableSort]);
+ this.draggable.off('sortable:sorted', this[onSortableSorted]);
+ }
+
+ /**
+ * Returns options passed through draggable
+ * @return {Object}
+ */
+ getOptions() {
+ return this.draggable.options.sortAnimation || {};
+ }
+
+ /**
+ * Sortable sort handler
+ * @param {SortableSortEvent} sortableEvent
+ * @private
+ */
+ [onSortableSort]({ dragEvent }) {
+ const { sourceContainer } = dragEvent;
+ const elements = this.draggable.getDraggableElementsForContainer(sourceContainer);
+ this.lastElements = Array.from(elements).map(el => {
+ return {
+ domEl: el,
+ offsetTop: el.offsetTop,
+ offsetLeft: el.offsetLeft
+ };
+ });
+ }
+
+ /**
+ * Sortable sorted handler
+ * @param {SortableSortedEvent} sortableEvent
+ * @private
+ */
+ [onSortableSorted]({ oldIndex, newIndex }) {
+ if (oldIndex === newIndex) {
+ return;
+ }
+
+ const effectedElements = [];
+ let start;
+ let end;
+ let num;
+ if (oldIndex > newIndex) {
+ start = newIndex;
+ end = oldIndex - 1;
+ num = 1;
+ } else {
+ start = oldIndex + 1;
+ end = newIndex;
+ num = -1;
+ }
+
+ for (let i = start; i <= end; i++) {
+ const from = this.lastElements[i];
+ const to = this.lastElements[i + num];
+ effectedElements.push({ from, to });
+ }
+ cancelAnimationFrame(this.lastAnimationFrame);
+
+ // Can be done in a separate frame
+ this.lastAnimationFrame = requestAnimationFrame(() => {
+ effectedElements.forEach(element => animate(element, this.options));
+ });
+ }
+}
+
+exports.default = SortAnimation; /**
+ * Animates two elements
+ * @param {Object} element
+ * @param {Object} element.from
+ * @param {Object} element.to
+ * @param {Object} options
+ * @param {Number} options.duration
+ * @param {String} options.easingFunction
+ * @private
+ */
+
+function animate({ from, to }, { duration, easingFunction }) {
+ const domEl = from.domEl;
+ const x = from.offsetLeft - to.offsetLeft;
+ const y = from.offsetTop - to.offsetTop;
+
+ domEl.style.pointerEvents = 'none';
+ domEl.style.transform = `translate3d(${x}px, ${y}px, 0)`;
+
+ requestAnimationFrame(() => {
+ domEl.addEventListener('transitionend', resetElementOnTransitionEnd);
+ domEl.style.transition = `transform ${duration}ms ${easingFunction}`;
+ domEl.style.transform = '';
+ });
+}
+
+/**
+ * Resets animation style properties after animation has completed
+ * @param {Event} event
+ * @private
+ */
+function resetElementOnTransitionEnd(event) {
+ event.target.style.transition = '';
+ event.target.style.pointerEvents = '';
+ event.target.removeEventListener('transitionend', resetElementOnTransitionEnd);
+}
+
+/***/ }),
+/* 16 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.defaultOptions = undefined;
+
+var _SortAnimation = __webpack_require__(15);
+
+var _SortAnimation2 = _interopRequireDefault(_SortAnimation);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _SortAnimation2.default;
+exports.defaultOptions = _SortAnimation.defaultOptions;
+
+/***/ }),
+/* 17 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.defaultOptions = undefined;
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _AbstractPlugin = __webpack_require__(0);
+
+var _AbstractPlugin2 = _interopRequireDefault(_AbstractPlugin);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+const onSortableSorted = Symbol('onSortableSorted');
+
+/**
+ * SwapAnimation default options
+ * @property {Object} defaultOptions
+ * @property {Number} defaultOptions.duration
+ * @property {String} defaultOptions.easingFunction
+ * @property {Boolean} defaultOptions.horizontal
+ * @type {Object}
+ */
+const defaultOptions = exports.defaultOptions = {
+ duration: 150,
+ easingFunction: 'ease-in-out',
+ horizontal: false
+};
+
+/**
+ * SwapAnimation plugin adds swap animations for sortable
+ * @class SwapAnimation
+ * @module SwapAnimation
+ * @extends AbstractPlugin
+ */
+class SwapAnimation extends _AbstractPlugin2.default {
+ /**
+ * SwapAnimation constructor.
+ * @constructs SwapAnimation
+ * @param {Draggable} draggable - Draggable instance
+ */
+ constructor(draggable) {
+ super(draggable);
+
+ /**
+ * SwapAnimation options
+ * @property {Object} options
+ * @property {Number} defaultOptions.duration
+ * @property {String} defaultOptions.easingFunction
+ * @type {Object}
+ */
+ this.options = _extends({}, defaultOptions, this.getOptions());
+
+ /**
+ * Last animation frame
+ * @property {Number} lastAnimationFrame
+ * @type {Number}
+ */
+ this.lastAnimationFrame = null;
+
+ this[onSortableSorted] = this[onSortableSorted].bind(this);
+ }
+
+ /**
+ * Attaches plugins event listeners
+ */
+ attach() {
+ this.draggable.on('sortable:sorted', this[onSortableSorted]);
+ }
+
+ /**
+ * Detaches plugins event listeners
+ */
+ detach() {
+ this.draggable.off('sortable:sorted', this[onSortableSorted]);
+ }
+
+ /**
+ * Returns options passed through draggable
+ * @return {Object}
+ */
+ getOptions() {
+ return this.draggable.options.swapAnimation || {};
+ }
+
+ /**
+ * Sortable sorted handler
+ * @param {SortableSortedEvent} sortableEvent
+ * @private
+ */
+ [onSortableSorted]({ oldIndex, newIndex, dragEvent }) {
+ const { source, over } = dragEvent;
+
+ cancelAnimationFrame(this.lastAnimationFrame);
+
+ // Can be done in a separate frame
+ this.lastAnimationFrame = requestAnimationFrame(() => {
+ if (oldIndex >= newIndex) {
+ animate(source, over, this.options);
+ } else {
+ animate(over, source, this.options);
+ }
+ });
+ }
+}
+
+exports.default = SwapAnimation; /**
+ * Animates two elements
+ * @param {HTMLElement} from
+ * @param {HTMLElement} to
+ * @param {Object} options
+ * @param {Number} options.duration
+ * @param {String} options.easingFunction
+ * @param {String} options.horizontal
+ * @private
+ */
+
+function animate(from, to, { duration, easingFunction, horizontal }) {
+ for (const element of [from, to]) {
+ element.style.pointerEvents = 'none';
+ }
+
+ if (horizontal) {
+ const width = from.offsetWidth;
+ from.style.transform = `translate3d(${width}px, 0, 0)`;
+ to.style.transform = `translate3d(-${width}px, 0, 0)`;
+ } else {
+ const height = from.offsetHeight;
+ from.style.transform = `translate3d(0, ${height}px, 0)`;
+ to.style.transform = `translate3d(0, -${height}px, 0)`;
+ }
+
+ requestAnimationFrame(() => {
+ for (const element of [from, to]) {
+ element.addEventListener('transitionend', resetElementOnTransitionEnd);
+ element.style.transition = `transform ${duration}ms ${easingFunction}`;
+ element.style.transform = '';
+ }
+ });
+}
+
+/**
+ * Resets animation style properties after animation has completed
+ * @param {Event} event
+ * @private
+ */
+function resetElementOnTransitionEnd(event) {
+ event.target.style.transition = '';
+ event.target.style.pointerEvents = '';
+ event.target.removeEventListener('transitionend', resetElementOnTransitionEnd);
+}
+
+/***/ }),
+/* 18 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.defaultOptions = undefined;
+
+var _SwapAnimation = __webpack_require__(17);
+
+var _SwapAnimation2 = _interopRequireDefault(_SwapAnimation);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _SwapAnimation2.default;
+exports.defaultOptions = _SwapAnimation.defaultOptions;
+
+/***/ }),
+/* 19 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _AbstractPlugin = __webpack_require__(0);
+
+var _AbstractPlugin2 = _interopRequireDefault(_AbstractPlugin);
+
+var _SnappableEvent = __webpack_require__(7);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+const onDragStart = Symbol('onDragStart');
+const onDragStop = Symbol('onDragStop');
+const onDragOver = Symbol('onDragOver');
+const onDragOut = Symbol('onDragOut');
+const onMirrorCreated = Symbol('onMirrorCreated');
+const onMirrorDestroy = Symbol('onMirrorDestroy');
+
+/**
+ * Snappable plugin which snaps draggable elements into place
+ * @class Snappable
+ * @module Snappable
+ * @extends AbstractPlugin
+ */
+class Snappable extends _AbstractPlugin2.default {
+ /**
+ * Snappable constructor.
+ * @constructs Snappable
+ * @param {Draggable} draggable - Draggable instance
+ */
+ constructor(draggable) {
+ super(draggable);
+
+ /**
+ * Keeps track of the first source element
+ * @property {HTMLElement|null} firstSource
+ */
+ this.firstSource = null;
+
+ /**
+ * Keeps track of the mirror element
+ * @property {HTMLElement} mirror
+ */
+ this.mirror = null;
+
+ this[onDragStart] = this[onDragStart].bind(this);
+ this[onDragStop] = this[onDragStop].bind(this);
+ this[onDragOver] = this[onDragOver].bind(this);
+ this[onDragOut] = this[onDragOut].bind(this);
+ this[onMirrorCreated] = this[onMirrorCreated].bind(this);
+ this[onMirrorDestroy] = this[onMirrorDestroy].bind(this);
+ }
+
+ /**
+ * Attaches plugins event listeners
+ */
+ attach() {
+ this.draggable.on('drag:start', this[onDragStart]).on('drag:stop', this[onDragStop]).on('drag:over', this[onDragOver]).on('drag:out', this[onDragOut]).on('droppable:over', this[onDragOver]).on('droppable:out', this[onDragOut]).on('mirror:created', this[onMirrorCreated]).on('mirror:destroy', this[onMirrorDestroy]);
+ }
+
+ /**
+ * Detaches plugins event listeners
+ */
+ detach() {
+ this.draggable.off('drag:start', this[onDragStart]).off('drag:stop', this[onDragStop]).off('drag:over', this[onDragOver]).off('drag:out', this[onDragOut]).off('droppable:over', this[onDragOver]).off('droppable:out', this[onDragOut]).off('mirror:created', this[onMirrorCreated]).off('mirror:destroy', this[onMirrorDestroy]);
+ }
+
+ /**
+ * Drag start handler
+ * @private
+ * @param {DragStartEvent} event - Drag start event
+ */
+ [onDragStart](event) {
+ if (event.canceled()) {
+ return;
+ }
+
+ this.firstSource = event.source;
+ }
+
+ /**
+ * Drag stop handler
+ * @private
+ * @param {DragStopEvent} event - Drag stop event
+ */
+ [onDragStop]() {
+ this.firstSource = null;
+ }
+
+ /**
+ * Drag over handler
+ * @private
+ * @param {DragOverEvent|DroppableOverEvent} event - Drag over event
+ */
+ [onDragOver](event) {
+ if (event.canceled()) {
+ return;
+ }
+
+ const source = event.source || event.dragEvent.source;
+
+ if (source === this.firstSource) {
+ this.firstSource = null;
+ return;
+ }
+
+ const snapInEvent = new _SnappableEvent.SnapInEvent({
+ dragEvent: event,
+ snappable: event.over || event.droppable
+ });
+
+ this.draggable.trigger(snapInEvent);
+
+ if (snapInEvent.canceled()) {
+ return;
+ }
+
+ if (this.mirror) {
+ this.mirror.style.display = 'none';
+ }
+
+ source.classList.remove(this.draggable.getClassNameFor('source:dragging'));
+ source.classList.add(this.draggable.getClassNameFor('source:placed'));
+
+ // Need to cancel this in drag out
+ setTimeout(() => {
+ source.classList.remove(this.draggable.getClassNameFor('source:placed'));
+ }, this.draggable.options.placedTimeout);
+ }
+
+ /**
+ * Drag out handler
+ * @private
+ * @param {DragOutEvent|DroppableOutEvent} event - Drag out event
+ */
+ [onDragOut](event) {
+ if (event.canceled()) {
+ return;
+ }
+
+ const source = event.source || event.dragEvent.source;
+
+ const snapOutEvent = new _SnappableEvent.SnapOutEvent({
+ dragEvent: event,
+ snappable: event.over || event.droppable
+ });
+
+ this.draggable.trigger(snapOutEvent);
+
+ if (snapOutEvent.canceled()) {
+ return;
+ }
+
+ if (this.mirror) {
+ this.mirror.style.display = '';
+ }
+
+ source.classList.add(this.draggable.getClassNameFor('source:dragging'));
+ }
+
+ /**
+ * Mirror created handler
+ * @param {MirrorCreatedEvent} mirrorEvent
+ * @private
+ */
+ [onMirrorCreated]({ mirror }) {
+ this.mirror = mirror;
+ }
+
+ /**
+ * Mirror destroy handler
+ * @param {MirrorDestroyEvent} mirrorEvent
+ * @private
+ */
+ [onMirrorDestroy]() {
+ this.mirror = null;
+ }
+}
+exports.default = Snappable;
+
+/***/ }),
+/* 20 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.SnapOutEvent = exports.SnapInEvent = exports.SnapEvent = undefined;
+
+var _AbstractEvent = __webpack_require__(1);
+
+var _AbstractEvent2 = _interopRequireDefault(_AbstractEvent);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/**
+ * Base snap event
+ * @class SnapEvent
+ * @module SnapEvent
+ * @extends AbstractEvent
+ */
+class SnapEvent extends _AbstractEvent2.default {
+
+ /**
+ * Drag event that triggered this snap event
+ * @property dragEvent
+ * @type {DragEvent}
+ * @readonly
+ */
+ get dragEvent() {
+ return this.data.dragEvent;
+ }
+
+ /**
+ * Snappable element
+ * @property snappable
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get snappable() {
+ return this.data.snappable;
+ }
+}
+
+exports.SnapEvent = SnapEvent; /**
+ * Snap in event
+ * @class SnapInEvent
+ * @module SnapInEvent
+ * @extends SnapEvent
+ */
+
+SnapEvent.type = 'snap';
+class SnapInEvent extends SnapEvent {}
+
+exports.SnapInEvent = SnapInEvent; /**
+ * Snap out event
+ * @class SnapOutEvent
+ * @module SnapOutEvent
+ * @extends SnapEvent
+ */
+
+SnapInEvent.type = 'snap:in';
+SnapInEvent.cancelable = true;
+class SnapOutEvent extends SnapEvent {}
+exports.SnapOutEvent = SnapOutEvent;
+SnapOutEvent.type = 'snap:out';
+SnapOutEvent.cancelable = true;
+
+/***/ }),
+/* 21 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _SnappableEvent = __webpack_require__(7);
+
+Object.keys(_SnappableEvent).forEach(function (key) {
+ if (key === "default" || key === "__esModule") return;
+ Object.defineProperty(exports, key, {
+ enumerable: true,
+ get: function () {
+ return _SnappableEvent[key];
+ }
+ });
+});
+
+var _Snappable = __webpack_require__(19);
+
+var _Snappable2 = _interopRequireDefault(_Snappable);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _Snappable2.default;
+
+/***/ }),
+/* 22 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.defaultOptions = undefined;
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _AbstractPlugin = __webpack_require__(0);
+
+var _AbstractPlugin2 = _interopRequireDefault(_AbstractPlugin);
+
+var _utils = __webpack_require__(2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+const onMirrorCreated = Symbol('onMirrorCreated');
+const onMirrorDestroy = Symbol('onMirrorDestroy');
+const onDragOver = Symbol('onDragOver');
+const resize = Symbol('resize');
+
+/**
+ * ResizeMirror default options
+ * @property {Object} defaultOptions
+ * @type {Object}
+ */
+const defaultOptions = exports.defaultOptions = {};
+
+/**
+ * The ResizeMirror plugin resizes the mirror element to the dimensions of the draggable element that the mirror is hovering over
+ * @class ResizeMirror
+ * @module ResizeMirror
+ * @extends AbstractPlugin
+ */
+class ResizeMirror extends _AbstractPlugin2.default {
+ /**
+ * ResizeMirror constructor.
+ * @constructs ResizeMirror
+ * @param {Draggable} draggable - Draggable instance
+ */
+ constructor(draggable) {
+ super(draggable);
+
+ /**
+ * ResizeMirror options
+ * @property {Object} options
+ * @type {Object}
+ */
+ this.options = _extends({}, defaultOptions, this.getOptions());
+
+ /**
+ * ResizeMirror remembers the last width when resizing the mirror
+ * to avoid additional writes to the DOM
+ * @property {number} lastWidth
+ */
+ this.lastWidth = 0;
+
+ /**
+ * ResizeMirror remembers the last height when resizing the mirror
+ * to avoid additional writes to the DOM
+ * @property {number} lastHeight
+ */
+ this.lastHeight = 0;
+
+ /**
+ * Keeps track of the mirror element
+ * @property {HTMLElement} mirror
+ */
+ this.mirror = null;
+
+ this[onMirrorCreated] = this[onMirrorCreated].bind(this);
+ this[onMirrorDestroy] = this[onMirrorDestroy].bind(this);
+ this[onDragOver] = this[onDragOver].bind(this);
+ }
+
+ /**
+ * Attaches plugins event listeners
+ */
+ attach() {
+ this.draggable.on('mirror:created', this[onMirrorCreated]).on('drag:over', this[onDragOver]).on('drag:over:container', this[onDragOver]);
+ }
+
+ /**
+ * Detaches plugins event listeners
+ */
+ detach() {
+ this.draggable.off('mirror:created', this[onMirrorCreated]).off('mirror:destroy', this[onMirrorDestroy]).off('drag:over', this[onDragOver]).off('drag:over:container', this[onDragOver]);
+ }
+
+ /**
+ * Returns options passed through draggable
+ * @return {Object}
+ */
+ getOptions() {
+ return this.draggable.options.resizeMirror || {};
+ }
+
+ /**
+ * Mirror created handler
+ * @param {MirrorCreatedEvent} mirrorEvent
+ * @private
+ */
+ [onMirrorCreated]({ mirror }) {
+ this.mirror = mirror;
+ }
+
+ /**
+ * Mirror destroy handler
+ * @param {MirrorDestroyEvent} mirrorEvent
+ * @private
+ */
+ [onMirrorDestroy]() {
+ this.mirror = null;
+ }
+
+ /**
+ * Drag over handler
+ * @param {DragOverEvent | DragOverContainer} dragEvent
+ * @private
+ */
+ [onDragOver](dragEvent) {
+ this[resize](dragEvent);
+ }
+
+ /**
+ * Resize function for
+ * @param {DragOverEvent | DragOverContainer} dragEvent
+ * @private
+ */
+ [resize]({ overContainer, over }) {
+ requestAnimationFrame(() => {
+ if (!this.mirror.parentNode) {
+ return;
+ }
+
+ if (this.mirror.parentNode !== overContainer) {
+ overContainer.appendChild(this.mirror);
+ }
+
+ const overElement = over || this.draggable.getDraggableElementsForContainer(overContainer)[0];
+
+ if (!overElement) {
+ return;
+ }
+
+ (0, _utils.requestNextAnimationFrame)(() => {
+ const overRect = overElement.getBoundingClientRect();
+
+ if (this.lastHeight === overRect.height && this.lastWidth === overRect.width) {
+ return;
+ }
+
+ this.mirror.style.width = `${overRect.width}px`;
+ this.mirror.style.height = `${overRect.height}px`;
+
+ this.lastWidth = overRect.width;
+ this.lastHeight = overRect.height;
+ });
+ });
+ }
+}
+exports.default = ResizeMirror;
+
+/***/ }),
+/* 23 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.defaultOptions = undefined;
+
+var _ResizeMirror = __webpack_require__(22);
+
+var _ResizeMirror2 = _interopRequireDefault(_ResizeMirror);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _ResizeMirror2.default;
+exports.defaultOptions = _ResizeMirror.defaultOptions;
+
+/***/ }),
+/* 24 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _AbstractPlugin = __webpack_require__(0);
+
+var _AbstractPlugin2 = _interopRequireDefault(_AbstractPlugin);
+
+var _utils = __webpack_require__(2);
+
+var _CollidableEvent = __webpack_require__(8);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+const onDragMove = Symbol('onDragMove');
+const onDragStop = Symbol('onDragStop');
+const onRequestAnimationFrame = Symbol('onRequestAnimationFrame');
+
+/**
+ * Collidable plugin which detects colliding elements while dragging
+ * @class Collidable
+ * @module Collidable
+ * @extends AbstractPlugin
+ */
+class Collidable extends _AbstractPlugin2.default {
+ /**
+ * Collidable constructor.
+ * @constructs Collidable
+ * @param {Draggable} draggable - Draggable instance
+ */
+ constructor(draggable) {
+ super(draggable);
+
+ /**
+ * Keeps track of currently colliding elements
+ * @property {HTMLElement|null} currentlyCollidingElement
+ * @type {HTMLElement|null}
+ */
+ this.currentlyCollidingElement = null;
+
+ /**
+ * Keeps track of currently colliding elements
+ * @property {HTMLElement|null} lastCollidingElement
+ * @type {HTMLElement|null}
+ */
+ this.lastCollidingElement = null;
+
+ /**
+ * Animation frame for finding colliding elements
+ * @property {Number|null} currentAnimationFrame
+ * @type {Number|null}
+ */
+ this.currentAnimationFrame = null;
+
+ this[onDragMove] = this[onDragMove].bind(this);
+ this[onDragStop] = this[onDragStop].bind(this);
+ this[onRequestAnimationFrame] = this[onRequestAnimationFrame].bind(this);
+ }
+
+ /**
+ * Attaches plugins event listeners
+ */
+ attach() {
+ this.draggable.on('drag:move', this[onDragMove]).on('drag:stop', this[onDragStop]);
+ }
+
+ /**
+ * Detaches plugins event listeners
+ */
+ detach() {
+ this.draggable.off('drag:move', this[onDragMove]).off('drag:stop', this[onDragStop]);
+ }
+
+ /**
+ * Returns current collidables based on `collidables` option
+ * @return {HTMLElement[]}
+ */
+ getCollidables() {
+ const collidables = this.draggable.options.collidables;
+
+ if (typeof collidables === 'string') {
+ return Array.prototype.slice.call(document.querySelectorAll(collidables));
+ } else if (collidables instanceof NodeList || collidables instanceof Array) {
+ return Array.prototype.slice.call(collidables);
+ } else if (collidables instanceof HTMLElement) {
+ return [collidables];
+ } else if (typeof collidables === 'function') {
+ return collidables();
+ } else {
+ return [];
+ }
+ }
+
+ /**
+ * Drag move handler
+ * @private
+ * @param {DragMoveEvent} event - Drag move event
+ */
+ [onDragMove](event) {
+ const target = event.sensorEvent.target;
+
+ this.currentAnimationFrame = requestAnimationFrame(this[onRequestAnimationFrame](target));
+
+ if (this.currentlyCollidingElement) {
+ event.cancel();
+ }
+
+ const collidableInEvent = new _CollidableEvent.CollidableInEvent({
+ dragEvent: event,
+ collidingElement: this.currentlyCollidingElement
+ });
+
+ const collidableOutEvent = new _CollidableEvent.CollidableOutEvent({
+ dragEvent: event,
+ collidingElement: this.lastCollidingElement
+ });
+
+ const enteringCollidable = Boolean(this.currentlyCollidingElement && this.lastCollidingElement !== this.currentlyCollidingElement);
+ const leavingCollidable = Boolean(!this.currentlyCollidingElement && this.lastCollidingElement);
+
+ if (enteringCollidable) {
+ if (this.lastCollidingElement) {
+ this.draggable.trigger(collidableOutEvent);
+ }
+
+ this.draggable.trigger(collidableInEvent);
+ } else if (leavingCollidable) {
+ this.draggable.trigger(collidableOutEvent);
+ }
+
+ this.lastCollidingElement = this.currentlyCollidingElement;
+ }
+
+ /**
+ * Drag stop handler
+ * @private
+ * @param {DragStopEvent} event - Drag stop event
+ */
+ [onDragStop](event) {
+ const lastCollidingElement = this.currentlyCollidingElement || this.lastCollidingElement;
+ const collidableOutEvent = new _CollidableEvent.CollidableOutEvent({
+ dragEvent: event,
+ collidingElement: lastCollidingElement
+ });
+
+ if (lastCollidingElement) {
+ this.draggable.trigger(collidableOutEvent);
+ }
+
+ this.lastCollidingElement = null;
+ this.currentlyCollidingElement = null;
+ }
+
+ /**
+ * Animation frame function
+ * @private
+ * @param {HTMLElement} target - Current move target
+ * @return {Function}
+ */
+ [onRequestAnimationFrame](target) {
+ return () => {
+ const collidables = this.getCollidables();
+ this.currentlyCollidingElement = (0, _utils.closest)(target, element => collidables.includes(element));
+ };
+ }
+}
+exports.default = Collidable;
+
+/***/ }),
+/* 25 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.CollidableOutEvent = exports.CollidableInEvent = exports.CollidableEvent = undefined;
+
+var _AbstractEvent = __webpack_require__(1);
+
+var _AbstractEvent2 = _interopRequireDefault(_AbstractEvent);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/**
+ * Base collidable event
+ * @class CollidableEvent
+ * @module CollidableEvent
+ * @extends AbstractEvent
+ */
+class CollidableEvent extends _AbstractEvent2.default {
+
+ /**
+ * Drag event that triggered this colliable event
+ * @property dragEvent
+ * @type {DragEvent}
+ * @readonly
+ */
+ get dragEvent() {
+ return this.data.dragEvent;
+ }
+}
+
+exports.CollidableEvent = CollidableEvent; /**
+ * Collidable in event
+ * @class CollidableInEvent
+ * @module CollidableInEvent
+ * @extends CollidableEvent
+ */
+
+CollidableEvent.type = 'collidable';
+class CollidableInEvent extends CollidableEvent {
+
+ /**
+ * Element you are currently colliding with
+ * @property collidingElement
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get collidingElement() {
+ return this.data.collidingElement;
+ }
+}
+
+exports.CollidableInEvent = CollidableInEvent; /**
+ * Collidable out event
+ * @class CollidableOutEvent
+ * @module CollidableOutEvent
+ * @extends CollidableEvent
+ */
+
+CollidableInEvent.type = 'collidable:in';
+class CollidableOutEvent extends CollidableEvent {
+
+ /**
+ * Element you were previously colliding with
+ * @property collidingElement
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get collidingElement() {
+ return this.data.collidingElement;
+ }
+}
+exports.CollidableOutEvent = CollidableOutEvent;
+CollidableOutEvent.type = 'collidable:out';
+
+/***/ }),
+/* 26 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _CollidableEvent = __webpack_require__(8);
+
+Object.keys(_CollidableEvent).forEach(function (key) {
+ if (key === "default" || key === "__esModule") return;
+ Object.defineProperty(exports, key, {
+ enumerable: true,
+ get: function () {
+ return _CollidableEvent[key];
+ }
+ });
+});
+
+var _Collidable = __webpack_require__(24);
+
+var _Collidable2 = _interopRequireDefault(_Collidable);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _Collidable2.default;
+
+/***/ }),
+/* 27 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _Collidable = __webpack_require__(26);
+
+Object.defineProperty(exports, 'Collidable', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_Collidable).default;
+ }
+});
+
+var _ResizeMirror = __webpack_require__(23);
+
+Object.defineProperty(exports, 'ResizeMirror', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_ResizeMirror).default;
+ }
+});
+Object.defineProperty(exports, 'defaultResizeMirrorOptions', {
+ enumerable: true,
+ get: function () {
+ return _ResizeMirror.defaultOptions;
+ }
+});
+
+var _Snappable = __webpack_require__(21);
+
+Object.defineProperty(exports, 'Snappable', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_Snappable).default;
+ }
+});
+
+var _SwapAnimation = __webpack_require__(18);
+
+Object.defineProperty(exports, 'SwapAnimation', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_SwapAnimation).default;
+ }
+});
+Object.defineProperty(exports, 'defaultSwapAnimationOptions', {
+ enumerable: true,
+ get: function () {
+ return _SwapAnimation.defaultOptions;
+ }
+});
+
+var _SortAnimation = __webpack_require__(16);
+
+Object.defineProperty(exports, 'SortAnimation', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_SortAnimation).default;
+ }
+});
+Object.defineProperty(exports, 'defaultSortAnimationOptions', {
+ enumerable: true,
+ get: function () {
+ return _SortAnimation.defaultOptions;
+ }
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/***/ }),
+/* 28 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _Draggable = __webpack_require__(5);
+
+var _Draggable2 = _interopRequireDefault(_Draggable);
+
+var _SortableEvent = __webpack_require__(9);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+const onDragStart = Symbol('onDragStart');
+const onDragOverContainer = Symbol('onDragOverContainer');
+const onDragOver = Symbol('onDragOver');
+const onDragStop = Symbol('onDragStop');
+
+/**
+ * Returns announcement message when a Draggable element has been sorted with another Draggable element
+ * or moved into a new container
+ * @param {SortableSortedEvent} sortableEvent
+ * @return {String}
+ */
+function onSortableSortedDefaultAnnouncement({ dragEvent }) {
+ const sourceText = dragEvent.source.textContent.trim() || dragEvent.source.id || 'sortable element';
+
+ if (dragEvent.over) {
+ const overText = dragEvent.over.textContent.trim() || dragEvent.over.id || 'sortable element';
+ const isFollowing = dragEvent.source.compareDocumentPosition(dragEvent.over) & Node.DOCUMENT_POSITION_FOLLOWING;
+
+ if (isFollowing) {
+ return `Placed ${sourceText} after ${overText}`;
+ } else {
+ return `Placed ${sourceText} before ${overText}`;
+ }
+ } else {
+ // need to figure out how to compute container name
+ return `Placed ${sourceText} into a different container`;
+ }
+}
+
+/**
+ * @const {Object} defaultAnnouncements
+ * @const {Function} defaultAnnouncements['sortable:sorted']
+ */
+const defaultAnnouncements = {
+ 'sortable:sorted': onSortableSortedDefaultAnnouncement
+};
+
+/**
+ * Sortable is built on top of Draggable and allows sorting of draggable elements. Sortable will keep
+ * track of the original index and emits the new index as you drag over draggable elements.
+ * @class Sortable
+ * @module Sortable
+ * @extends Draggable
+ */
+class Sortable extends _Draggable2.default {
+ /**
+ * Sortable constructor.
+ * @constructs Sortable
+ * @param {HTMLElement[]|NodeList|HTMLElement} containers - Sortable containers
+ * @param {Object} options - Options for Sortable
+ */
+ constructor(containers = [], options = {}) {
+ super(containers, _extends({}, options, {
+ announcements: _extends({}, defaultAnnouncements, options.announcements || {})
+ }));
+
+ /**
+ * start index of source on drag start
+ * @property startIndex
+ * @type {Number}
+ */
+ this.startIndex = null;
+
+ /**
+ * start container on drag start
+ * @property startContainer
+ * @type {HTMLElement}
+ * @default null
+ */
+ this.startContainer = null;
+
+ this[onDragStart] = this[onDragStart].bind(this);
+ this[onDragOverContainer] = this[onDragOverContainer].bind(this);
+ this[onDragOver] = this[onDragOver].bind(this);
+ this[onDragStop] = this[onDragStop].bind(this);
+
+ this.on('drag:start', this[onDragStart]).on('drag:over:container', this[onDragOverContainer]).on('drag:over', this[onDragOver]).on('drag:stop', this[onDragStop]);
+ }
+
+ /**
+ * Destroys Sortable instance.
+ */
+ destroy() {
+ super.destroy();
+
+ this.off('drag:start', this[onDragStart]).off('drag:over:container', this[onDragOverContainer]).off('drag:over', this[onDragOver]).off('drag:stop', this[onDragStop]);
+ }
+
+ /**
+ * Returns true index of element within its container during drag operation, i.e. excluding mirror and original source
+ * @param {HTMLElement} element - An element
+ * @return {Number}
+ */
+ index(element) {
+ return this.getDraggableElementsForContainer(element.parentNode).indexOf(element);
+ }
+
+ /**
+ * Drag start handler
+ * @private
+ * @param {DragStartEvent} event - Drag start event
+ */
+ [onDragStart](event) {
+ this.startContainer = event.source.parentNode;
+ this.startIndex = this.index(event.source);
+
+ const sortableStartEvent = new _SortableEvent.SortableStartEvent({
+ dragEvent: event,
+ startIndex: this.startIndex,
+ startContainer: this.startContainer
+ });
+
+ this.trigger(sortableStartEvent);
+
+ if (sortableStartEvent.canceled()) {
+ event.cancel();
+ }
+ }
+
+ /**
+ * Drag over container handler
+ * @private
+ * @param {DragOverContainerEvent} event - Drag over container event
+ */
+ [onDragOverContainer](event) {
+ if (event.canceled()) {
+ return;
+ }
+
+ const { source, over, overContainer } = event;
+ const oldIndex = this.index(source);
+
+ const sortableSortEvent = new _SortableEvent.SortableSortEvent({
+ dragEvent: event,
+ currentIndex: oldIndex,
+ source,
+ over
+ });
+
+ this.trigger(sortableSortEvent);
+
+ if (sortableSortEvent.canceled()) {
+ return;
+ }
+
+ const children = this.getDraggableElementsForContainer(overContainer);
+ const moves = move({ source, over, overContainer, children });
+
+ if (!moves) {
+ return;
+ }
+
+ const { oldContainer, newContainer } = moves;
+ const newIndex = this.index(event.source);
+
+ const sortableSortedEvent = new _SortableEvent.SortableSortedEvent({
+ dragEvent: event,
+ oldIndex,
+ newIndex,
+ oldContainer,
+ newContainer
+ });
+
+ this.trigger(sortableSortedEvent);
+ }
+
+ /**
+ * Drag over handler
+ * @private
+ * @param {DragOverEvent} event - Drag over event
+ */
+ [onDragOver](event) {
+ if (event.over === event.originalSource || event.over === event.source) {
+ return;
+ }
+
+ const { source, over, overContainer } = event;
+ const oldIndex = this.index(source);
+
+ const sortableSortEvent = new _SortableEvent.SortableSortEvent({
+ dragEvent: event,
+ currentIndex: oldIndex,
+ source,
+ over
+ });
+
+ this.trigger(sortableSortEvent);
+
+ if (sortableSortEvent.canceled()) {
+ return;
+ }
+
+ const children = this.getDraggableElementsForContainer(overContainer);
+ const moves = move({ source, over, overContainer, children });
+
+ if (!moves) {
+ return;
+ }
+
+ const { oldContainer, newContainer } = moves;
+ const newIndex = this.index(source);
+
+ const sortableSortedEvent = new _SortableEvent.SortableSortedEvent({
+ dragEvent: event,
+ oldIndex,
+ newIndex,
+ oldContainer,
+ newContainer
+ });
+
+ this.trigger(sortableSortedEvent);
+ }
+
+ /**
+ * Drag stop handler
+ * @private
+ * @param {DragStopEvent} event - Drag stop event
+ */
+ [onDragStop](event) {
+ const sortableStopEvent = new _SortableEvent.SortableStopEvent({
+ dragEvent: event,
+ oldIndex: this.startIndex,
+ newIndex: this.index(event.source),
+ oldContainer: this.startContainer,
+ newContainer: event.source.parentNode
+ });
+
+ this.trigger(sortableStopEvent);
+
+ this.startIndex = null;
+ this.startContainer = null;
+ }
+}
+
+exports.default = Sortable;
+function index(element) {
+ return Array.prototype.indexOf.call(element.parentNode.children, element);
+}
+
+function move({ source, over, overContainer, children }) {
+ const emptyOverContainer = !children.length;
+ const differentContainer = source.parentNode !== overContainer;
+ const sameContainer = over && !differentContainer;
+
+ if (emptyOverContainer) {
+ return moveInsideEmptyContainer(source, overContainer);
+ } else if (sameContainer) {
+ return moveWithinContainer(source, over);
+ } else if (differentContainer) {
+ return moveOutsideContainer(source, over, overContainer);
+ } else {
+ return null;
+ }
+}
+
+function moveInsideEmptyContainer(source, overContainer) {
+ const oldContainer = source.parentNode;
+
+ overContainer.appendChild(source);
+
+ return { oldContainer, newContainer: overContainer };
+}
+
+function moveWithinContainer(source, over) {
+ const oldIndex = index(source);
+ const newIndex = index(over);
+
+ if (oldIndex < newIndex) {
+ source.parentNode.insertBefore(source, over.nextElementSibling);
+ } else {
+ source.parentNode.insertBefore(source, over);
+ }
+
+ return { oldContainer: source.parentNode, newContainer: source.parentNode };
+}
+
+function moveOutsideContainer(source, over, overContainer) {
+ const oldContainer = source.parentNode;
+
+ if (over) {
+ over.parentNode.insertBefore(source, over);
+ } else {
+ // need to figure out proper position
+ overContainer.appendChild(source);
+ }
+
+ return { oldContainer, newContainer: source.parentNode };
+}
+
+/***/ }),
+/* 29 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.SortableStopEvent = exports.SortableSortedEvent = exports.SortableSortEvent = exports.SortableStartEvent = exports.SortableEvent = undefined;
+
+var _AbstractEvent = __webpack_require__(1);
+
+var _AbstractEvent2 = _interopRequireDefault(_AbstractEvent);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/**
+ * Base sortable event
+ * @class SortableEvent
+ * @module SortableEvent
+ * @extends AbstractEvent
+ */
+class SortableEvent extends _AbstractEvent2.default {
+
+ /**
+ * Original drag event that triggered this sortable event
+ * @property dragEvent
+ * @type {DragEvent}
+ * @readonly
+ */
+ get dragEvent() {
+ return this.data.dragEvent;
+ }
+}
+
+exports.SortableEvent = SortableEvent; /**
+ * Sortable start event
+ * @class SortableStartEvent
+ * @module SortableStartEvent
+ * @extends SortableEvent
+ */
+
+SortableEvent.type = 'sortable';
+class SortableStartEvent extends SortableEvent {
+
+ /**
+ * Start index of source on sortable start
+ * @property startIndex
+ * @type {Number}
+ * @readonly
+ */
+ get startIndex() {
+ return this.data.startIndex;
+ }
+
+ /**
+ * Start container on sortable start
+ * @property startContainer
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get startContainer() {
+ return this.data.startContainer;
+ }
+}
+
+exports.SortableStartEvent = SortableStartEvent; /**
+ * Sortable sort event
+ * @class SortableSortEvent
+ * @module SortableSortEvent
+ * @extends SortableEvent
+ */
+
+SortableStartEvent.type = 'sortable:start';
+SortableStartEvent.cancelable = true;
+class SortableSortEvent extends SortableEvent {
+
+ /**
+ * Index of current draggable element
+ * @property currentIndex
+ * @type {Number}
+ * @readonly
+ */
+ get currentIndex() {
+ return this.data.currentIndex;
+ }
+
+ /**
+ * Draggable element you are hovering over
+ * @property over
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get over() {
+ return this.data.over;
+ }
+
+ /**
+ * Draggable container element you are hovering over
+ * @property overContainer
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get overContainer() {
+ return this.data.dragEvent.overContainer;
+ }
+}
+
+exports.SortableSortEvent = SortableSortEvent; /**
+ * Sortable sorted event
+ * @class SortableSortedEvent
+ * @module SortableSortedEvent
+ * @extends SortableEvent
+ */
+
+SortableSortEvent.type = 'sortable:sort';
+SortableSortEvent.cancelable = true;
+class SortableSortedEvent extends SortableEvent {
+
+ /**
+ * Index of last sorted event
+ * @property oldIndex
+ * @type {Number}
+ * @readonly
+ */
+ get oldIndex() {
+ return this.data.oldIndex;
+ }
+
+ /**
+ * New index of this sorted event
+ * @property newIndex
+ * @type {Number}
+ * @readonly
+ */
+ get newIndex() {
+ return this.data.newIndex;
+ }
+
+ /**
+ * Old container of draggable element
+ * @property oldContainer
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get oldContainer() {
+ return this.data.oldContainer;
+ }
+
+ /**
+ * New container of draggable element
+ * @property newContainer
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get newContainer() {
+ return this.data.newContainer;
+ }
+}
+
+exports.SortableSortedEvent = SortableSortedEvent; /**
+ * Sortable stop event
+ * @class SortableStopEvent
+ * @module SortableStopEvent
+ * @extends SortableEvent
+ */
+
+SortableSortedEvent.type = 'sortable:sorted';
+class SortableStopEvent extends SortableEvent {
+
+ /**
+ * Original index on sortable start
+ * @property oldIndex
+ * @type {Number}
+ * @readonly
+ */
+ get oldIndex() {
+ return this.data.oldIndex;
+ }
+
+ /**
+ * New index of draggable element
+ * @property newIndex
+ * @type {Number}
+ * @readonly
+ */
+ get newIndex() {
+ return this.data.newIndex;
+ }
+
+ /**
+ * Original container of draggable element
+ * @property oldContainer
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get oldContainer() {
+ return this.data.oldContainer;
+ }
+
+ /**
+ * New container of draggable element
+ * @property newContainer
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get newContainer() {
+ return this.data.newContainer;
+ }
+}
+exports.SortableStopEvent = SortableStopEvent;
+SortableStopEvent.type = 'sortable:stop';
+
+/***/ }),
+/* 30 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _SortableEvent = __webpack_require__(9);
+
+Object.keys(_SortableEvent).forEach(function (key) {
+ if (key === "default" || key === "__esModule") return;
+ Object.defineProperty(exports, key, {
+ enumerable: true,
+ get: function () {
+ return _SortableEvent[key];
+ }
+ });
+});
+
+var _Sortable = __webpack_require__(28);
+
+var _Sortable2 = _interopRequireDefault(_Sortable);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _Sortable2.default;
+
+/***/ }),
+/* 31 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _Draggable = __webpack_require__(5);
+
+var _Draggable2 = _interopRequireDefault(_Draggable);
+
+var _SwappableEvent = __webpack_require__(10);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+const onDragStart = Symbol('onDragStart');
+const onDragOver = Symbol('onDragOver');
+const onDragStop = Symbol('onDragStop');
+
+/**
+ * Returns an announcement message when the Draggable element is swapped with another draggable element
+ * @param {SwappableSwappedEvent} swappableEvent
+ * @return {String}
+ */
+function onSwappableSwappedDefaultAnnouncement({ dragEvent, swappedElement }) {
+ const sourceText = dragEvent.source.textContent.trim() || dragEvent.source.id || 'swappable element';
+ const overText = swappedElement.textContent.trim() || swappedElement.id || 'swappable element';
+
+ return `Swapped ${sourceText} with ${overText}`;
+}
+
+/**
+ * @const {Object} defaultAnnouncements
+ * @const {Function} defaultAnnouncements['swappabled:swapped']
+ */
+const defaultAnnouncements = {
+ 'swappabled:swapped': onSwappableSwappedDefaultAnnouncement
+};
+
+/**
+ * Swappable is built on top of Draggable and allows swapping of draggable elements.
+ * Order is irrelevant to Swappable.
+ * @class Swappable
+ * @module Swappable
+ * @extends Draggable
+ */
+class Swappable extends _Draggable2.default {
+ /**
+ * Swappable constructor.
+ * @constructs Swappable
+ * @param {HTMLElement[]|NodeList|HTMLElement} containers - Swappable containers
+ * @param {Object} options - Options for Swappable
+ */
+ constructor(containers = [], options = {}) {
+ super(containers, _extends({}, options, {
+ announcements: _extends({}, defaultAnnouncements, options.announcements || {})
+ }));
+
+ /**
+ * Last draggable element that was dragged over
+ * @property lastOver
+ * @type {HTMLElement}
+ */
+ this.lastOver = null;
+
+ this[onDragStart] = this[onDragStart].bind(this);
+ this[onDragOver] = this[onDragOver].bind(this);
+ this[onDragStop] = this[onDragStop].bind(this);
+
+ this.on('drag:start', this[onDragStart]).on('drag:over', this[onDragOver]).on('drag:stop', this[onDragStop]);
+ }
+
+ /**
+ * Destroys Swappable instance.
+ */
+ destroy() {
+ super.destroy();
+
+ this.off('drag:start', this._onDragStart).off('drag:over', this._onDragOver).off('drag:stop', this._onDragStop);
+ }
+
+ /**
+ * Drag start handler
+ * @private
+ * @param {DragStartEvent} event - Drag start event
+ */
+ [onDragStart](event) {
+ const swappableStartEvent = new _SwappableEvent.SwappableStartEvent({
+ dragEvent: event
+ });
+
+ this.trigger(swappableStartEvent);
+
+ if (swappableStartEvent.canceled()) {
+ event.cancel();
+ }
+ }
+
+ /**
+ * Drag over handler
+ * @private
+ * @param {DragOverEvent} event - Drag over event
+ */
+ [onDragOver](event) {
+ if (event.over === event.originalSource || event.over === event.source || event.canceled()) {
+ return;
+ }
+
+ const swappableSwapEvent = new _SwappableEvent.SwappableSwapEvent({
+ dragEvent: event,
+ over: event.over,
+ overContainer: event.overContainer
+ });
+
+ this.trigger(swappableSwapEvent);
+
+ if (swappableSwapEvent.canceled()) {
+ return;
+ }
+
+ // swap originally swapped element back
+ if (this.lastOver && this.lastOver !== event.over) {
+ swap(this.lastOver, event.source);
+ }
+
+ if (this.lastOver === event.over) {
+ this.lastOver = null;
+ } else {
+ this.lastOver = event.over;
+ }
+
+ swap(event.source, event.over);
+
+ const swappableSwappedEvent = new _SwappableEvent.SwappableSwappedEvent({
+ dragEvent: event,
+ swappedElement: event.over
+ });
+
+ this.trigger(swappableSwappedEvent);
+ }
+
+ /**
+ * Drag stop handler
+ * @private
+ * @param {DragStopEvent} event - Drag stop event
+ */
+ [onDragStop](event) {
+ const swappableStopEvent = new _SwappableEvent.SwappableStopEvent({
+ dragEvent: event
+ });
+
+ this.trigger(swappableStopEvent);
+ this.lastOver = null;
+ }
+}
+
+exports.default = Swappable;
+function withTempElement(callback) {
+ const tmpElement = document.createElement('div');
+ callback(tmpElement);
+ tmpElement.parentNode.removeChild(tmpElement);
+}
+
+function swap(source, over) {
+ const overParent = over.parentNode;
+ const sourceParent = source.parentNode;
+
+ withTempElement(tmpElement => {
+ sourceParent.insertBefore(tmpElement, source);
+ overParent.insertBefore(source, over);
+ sourceParent.insertBefore(over, tmpElement);
+ });
+}
+
+/***/ }),
+/* 32 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.SwappableStopEvent = exports.SwappableSwappedEvent = exports.SwappableSwapEvent = exports.SwappableStartEvent = exports.SwappableEvent = undefined;
+
+var _AbstractEvent = __webpack_require__(1);
+
+var _AbstractEvent2 = _interopRequireDefault(_AbstractEvent);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/**
+ * Base swappable event
+ * @class SwappableEvent
+ * @module SwappableEvent
+ * @extends AbstractEvent
+ */
+class SwappableEvent extends _AbstractEvent2.default {
+
+ /**
+ * Original drag event that triggered this swappable event
+ * @property dragEvent
+ * @type {DragEvent}
+ * @readonly
+ */
+ get dragEvent() {
+ return this.data.dragEvent;
+ }
+}
+
+exports.SwappableEvent = SwappableEvent; /**
+ * Swappable start event
+ * @class SwappableStartEvent
+ * @module SwappableStartEvent
+ * @extends SwappableEvent
+ */
+
+SwappableEvent.type = 'swappable';
+class SwappableStartEvent extends SwappableEvent {}
+
+exports.SwappableStartEvent = SwappableStartEvent; /**
+ * Swappable swap event
+ * @class SwappableSwapEvent
+ * @module SwappableSwapEvent
+ * @extends SwappableEvent
+ */
+
+SwappableStartEvent.type = 'swappable:start';
+SwappableStartEvent.cancelable = true;
+class SwappableSwapEvent extends SwappableEvent {
+
+ /**
+ * Draggable element you are over
+ * @property over
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get over() {
+ return this.data.over;
+ }
+
+ /**
+ * Draggable container you are over
+ * @property overContainer
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get overContainer() {
+ return this.data.overContainer;
+ }
+}
+
+exports.SwappableSwapEvent = SwappableSwapEvent; /**
+ * Swappable swapped event
+ * @class SwappableSwappedEvent
+ * @module SwappableSwappedEvent
+ * @extends SwappableEvent
+ */
+
+SwappableSwapEvent.type = 'swappable:swap';
+SwappableSwapEvent.cancelable = true;
+class SwappableSwappedEvent extends SwappableEvent {
+
+ /**
+ * The draggable element that you swapped with
+ * @property swappedElement
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get swappedElement() {
+ return this.data.swappedElement;
+ }
+}
+
+exports.SwappableSwappedEvent = SwappableSwappedEvent; /**
+ * Swappable stop event
+ * @class SwappableStopEvent
+ * @module SwappableStopEvent
+ * @extends SwappableEvent
+ */
+
+SwappableSwappedEvent.type = 'swappable:swapped';
+class SwappableStopEvent extends SwappableEvent {}
+exports.SwappableStopEvent = SwappableStopEvent;
+SwappableStopEvent.type = 'swappable:stop';
+
+/***/ }),
+/* 33 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _SwappableEvent = __webpack_require__(10);
+
+Object.keys(_SwappableEvent).forEach(function (key) {
+ if (key === "default" || key === "__esModule") return;
+ Object.defineProperty(exports, key, {
+ enumerable: true,
+ get: function () {
+ return _SwappableEvent[key];
+ }
+ });
+});
+
+var _Swappable = __webpack_require__(31);
+
+var _Swappable2 = _interopRequireDefault(_Swappable);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _Swappable2.default;
+
+/***/ }),
+/* 34 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _utils = __webpack_require__(2);
+
+var _Draggable = __webpack_require__(5);
+
+var _Draggable2 = _interopRequireDefault(_Draggable);
+
+var _DroppableEvent = __webpack_require__(11);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+const onDragStart = Symbol('onDragStart');
+const onDragMove = Symbol('onDragMove');
+const onDragStop = Symbol('onDragStop');
+const dropInDropzone = Symbol('dropInDropZone');
+const returnToOriginalDropzone = Symbol('returnToOriginalDropzone');
+const closestDropzone = Symbol('closestDropzone');
+const getDropzones = Symbol('getDropzones');
+
+/**
+ * Returns an announcement message when the Draggable element is dropped into a dropzone element
+ * @param {DroppableDroppedEvent} droppableEvent
+ * @return {String}
+ */
+function onDroppableDroppedDefaultAnnouncement({ dragEvent, dropzone }) {
+ const sourceText = dragEvent.source.textContent.trim() || dragEvent.source.id || 'draggable element';
+ const dropzoneText = dropzone.textContent.trim() || dropzone.id || 'droppable element';
+
+ return `Dropped ${sourceText} into ${dropzoneText}`;
+}
+
+/**
+ * Returns an announcement message when the Draggable element has returned to its original dropzone element
+ * @param {DroppableReturnedEvent} droppableEvent
+ * @return {String}
+ */
+function onDroppableReturnedDefaultAnnouncement({ dragEvent, dropzone }) {
+ const sourceText = dragEvent.source.textContent.trim() || dragEvent.source.id || 'draggable element';
+ const dropzoneText = dropzone.textContent.trim() || dropzone.id || 'droppable element';
+
+ return `Returned ${sourceText} from ${dropzoneText}`;
+}
+
+/**
+ * @const {Object} defaultAnnouncements
+ * @const {Function} defaultAnnouncements['droppable:dropped']
+ * @const {Function} defaultAnnouncements['droppable:returned']
+ */
+const defaultAnnouncements = {
+ 'droppable:dropped': onDroppableDroppedDefaultAnnouncement,
+ 'droppable:returned': onDroppableReturnedDefaultAnnouncement
+};
+
+const defaultClasses = {
+ 'droppable:active': 'draggable-dropzone--active',
+ 'droppable:occupied': 'draggable-dropzone--occupied'
+};
+
+const defaultOptions = {
+ dropzone: '.draggable-droppable'
+};
+
+/**
+ * Droppable is built on top of Draggable and allows dropping draggable elements
+ * into dropzone element
+ * @class Droppable
+ * @module Droppable
+ * @extends Draggable
+ */
+class Droppable extends _Draggable2.default {
+ /**
+ * Droppable constructor.
+ * @constructs Droppable
+ * @param {HTMLElement[]|NodeList|HTMLElement} containers - Droppable containers
+ * @param {Object} options - Options for Droppable
+ */
+ constructor(containers = [], options = {}) {
+ super(containers, _extends({}, defaultOptions, options, {
+ classes: _extends({}, defaultClasses, options.classes || {}),
+ announcements: _extends({}, defaultAnnouncements, options.announcements || {})
+ }));
+
+ /**
+ * All dropzone elements on drag start
+ * @property dropzones
+ * @type {HTMLElement[]}
+ */
+ this.dropzones = null;
+
+ /**
+ * Last dropzone element that the source was dropped into
+ * @property lastDropzone
+ * @type {HTMLElement}
+ */
+ this.lastDropzone = null;
+
+ /**
+ * Initial dropzone element that the source was drag from
+ * @property initialDropzone
+ * @type {HTMLElement}
+ */
+ this.initialDropzone = null;
+
+ this[onDragStart] = this[onDragStart].bind(this);
+ this[onDragMove] = this[onDragMove].bind(this);
+ this[onDragStop] = this[onDragStop].bind(this);
+
+ this.on('drag:start', this[onDragStart]).on('drag:move', this[onDragMove]).on('drag:stop', this[onDragStop]);
+ }
+
+ /**
+ * Destroys Droppable instance.
+ */
+ destroy() {
+ super.destroy();
+
+ this.off('drag:start', this[onDragStart]).off('drag:move', this[onDragMove]).off('drag:stop', this[onDragStop]);
+ }
+
+ /**
+ * Drag start handler
+ * @private
+ * @param {DragStartEvent} event - Drag start event
+ */
+ [onDragStart](event) {
+ if (event.canceled()) {
+ return;
+ }
+
+ this.dropzones = [...this[getDropzones]()];
+ const dropzone = (0, _utils.closest)(event.sensorEvent.target, this.options.dropzone);
+
+ if (!dropzone) {
+ event.cancel();
+ return;
+ }
+
+ const droppableStartEvent = new _DroppableEvent.DroppableStartEvent({
+ dragEvent: event,
+ dropzone
+ });
+
+ this.trigger(droppableStartEvent);
+
+ if (droppableStartEvent.canceled()) {
+ event.cancel();
+ return;
+ }
+
+ this.initialDropzone = dropzone;
+
+ for (const dropzoneElement of this.dropzones) {
+ if (dropzoneElement.classList.contains(this.getClassNameFor('droppable:occupied'))) {
+ continue;
+ }
+
+ dropzoneElement.classList.add(this.getClassNameFor('droppable:active'));
+ }
+ }
+
+ /**
+ * Drag move handler
+ * @private
+ * @param {DragMoveEvent} event - Drag move event
+ */
+ [onDragMove](event) {
+ if (event.canceled()) {
+ return;
+ }
+
+ const dropzone = this[closestDropzone](event.sensorEvent.target);
+ const overEmptyDropzone = dropzone && !dropzone.classList.contains(this.getClassNameFor('droppable:occupied'));
+
+ if (overEmptyDropzone && this[dropInDropzone](event, dropzone)) {
+ this.lastDropzone = dropzone;
+ } else if ((!dropzone || dropzone === this.initialDropzone) && this.lastDropzone) {
+ this[returnToOriginalDropzone](event);
+ this.lastDropzone = null;
+ }
+ }
+
+ /**
+ * Drag stop handler
+ * @private
+ * @param {DragStopEvent} event - Drag stop event
+ */
+ [onDragStop](event) {
+ const droppableStopEvent = new _DroppableEvent.DroppableStopEvent({
+ dragEvent: event,
+ dropzone: this.lastDropzone || this.initialDropzone
+ });
+
+ this.trigger(droppableStopEvent);
+
+ const occupiedClass = this.getClassNameFor('droppable:occupied');
+
+ for (const dropzone of this.dropzones) {
+ dropzone.classList.remove(this.getClassNameFor('droppable:active'));
+ }
+
+ if (this.lastDropzone && this.lastDropzone !== this.initialDropzone) {
+ this.initialDropzone.classList.remove(occupiedClass);
+ }
+
+ this.dropzones = null;
+ this.lastDropzone = null;
+ this.initialDropzone = null;
+ }
+
+ /**
+ * Drops a draggable element into a dropzone element
+ * @private
+ * @param {DragMoveEvent} event - Drag move event
+ * @param {HTMLElement} dropzone - Dropzone element to drop draggable into
+ */
+ [dropInDropzone](event, dropzone) {
+ const droppableDroppedEvent = new _DroppableEvent.DroppableDroppedEvent({
+ dragEvent: event,
+ dropzone
+ });
+
+ this.trigger(droppableDroppedEvent);
+
+ if (droppableDroppedEvent.canceled()) {
+ return false;
+ }
+
+ const occupiedClass = this.getClassNameFor('droppable:occupied');
+
+ if (this.lastDropzone) {
+ this.lastDropzone.classList.remove(occupiedClass);
+ }
+
+ dropzone.appendChild(event.source);
+ dropzone.classList.add(occupiedClass);
+
+ return true;
+ }
+
+ /**
+ * Moves the previously dropped element back into its original dropzone
+ * @private
+ * @param {DragMoveEvent} event - Drag move event
+ */
+ [returnToOriginalDropzone](event) {
+ const droppableReturnedEvent = new _DroppableEvent.DroppableReturnedEvent({
+ dragEvent: event,
+ dropzone: this.lastDropzone
+ });
+
+ this.trigger(droppableReturnedEvent);
+
+ if (droppableReturnedEvent.canceled()) {
+ return;
+ }
+
+ this.initialDropzone.appendChild(event.source);
+ this.lastDropzone.classList.remove(this.getClassNameFor('droppable:occupied'));
+ }
+
+ /**
+ * Returns closest dropzone element for even target
+ * @private
+ * @param {HTMLElement} target - Event target
+ * @return {HTMLElement|null}
+ */
+ [closestDropzone](target) {
+ if (!this.dropzones) {
+ return null;
+ }
+
+ return (0, _utils.closest)(target, this.dropzones);
+ }
+
+ /**
+ * Returns all current dropzone elements for this draggable instance
+ * @private
+ * @return {NodeList|HTMLElement[]|Array}
+ */
+ [getDropzones]() {
+ const dropzone = this.options.dropzone;
+
+ if (typeof dropzone === 'string') {
+ return document.querySelectorAll(dropzone);
+ } else if (dropzone instanceof NodeList || dropzone instanceof Array) {
+ return dropzone;
+ } else if (typeof dropzone === 'function') {
+ return dropzone();
+ } else {
+ return [];
+ }
+ }
+}
+exports.default = Droppable;
+
+/***/ }),
+/* 35 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.DroppableStopEvent = exports.DroppableReturnedEvent = exports.DroppableDroppedEvent = exports.DroppableStartEvent = exports.DroppableEvent = undefined;
+
+var _AbstractEvent = __webpack_require__(1);
+
+var _AbstractEvent2 = _interopRequireDefault(_AbstractEvent);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/**
+ * Base droppable event
+ * @class DroppableEvent
+ * @module DroppableEvent
+ * @extends AbstractEvent
+ */
+class DroppableEvent extends _AbstractEvent2.default {
+
+ /**
+ * Original drag event that triggered this droppable event
+ * @property dragEvent
+ * @type {DragEvent}
+ * @readonly
+ */
+ get dragEvent() {
+ return this.data.dragEvent;
+ }
+}
+
+exports.DroppableEvent = DroppableEvent; /**
+ * Droppable start event
+ * @class DroppableStartEvent
+ * @module DroppableStartEvent
+ * @extends DroppableEvent
+ */
+
+DroppableEvent.type = 'droppable';
+class DroppableStartEvent extends DroppableEvent {
+
+ /**
+ * The initial dropzone element of the currently dragging draggable element
+ * @property dropzone
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get dropzone() {
+ return this.data.dropzone;
+ }
+}
+
+exports.DroppableStartEvent = DroppableStartEvent; /**
+ * Droppable dropped event
+ * @class DroppableDroppedEvent
+ * @module DroppableDroppedEvent
+ * @extends DroppableEvent
+ */
+
+DroppableStartEvent.type = 'droppable:start';
+DroppableStartEvent.cancelable = true;
+class DroppableDroppedEvent extends DroppableEvent {
+
+ /**
+ * The dropzone element you dropped the draggable element into
+ * @property dropzone
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get dropzone() {
+ return this.data.dropzone;
+ }
+}
+
+exports.DroppableDroppedEvent = DroppableDroppedEvent; /**
+ * Droppable returned event
+ * @class DroppableReturnedEvent
+ * @module DroppableReturnedEvent
+ * @extends DroppableEvent
+ */
+
+DroppableDroppedEvent.type = 'droppable:dropped';
+DroppableDroppedEvent.cancelable = true;
+class DroppableReturnedEvent extends DroppableEvent {
+
+ /**
+ * The dropzone element you dragged away from
+ * @property dropzone
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get dropzone() {
+ return this.data.dropzone;
+ }
+}
+
+exports.DroppableReturnedEvent = DroppableReturnedEvent; /**
+ * Droppable stop event
+ * @class DroppableStopEvent
+ * @module DroppableStopEvent
+ * @extends DroppableEvent
+ */
+
+DroppableReturnedEvent.type = 'droppable:returned';
+DroppableReturnedEvent.cancelable = true;
+class DroppableStopEvent extends DroppableEvent {
+
+ /**
+ * The final dropzone element of the draggable element
+ * @property dropzone
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get dropzone() {
+ return this.data.dropzone;
+ }
+}
+exports.DroppableStopEvent = DroppableStopEvent;
+DroppableStopEvent.type = 'droppable:stop';
+DroppableStopEvent.cancelable = true;
+
+/***/ }),
+/* 36 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _DroppableEvent = __webpack_require__(11);
+
+Object.keys(_DroppableEvent).forEach(function (key) {
+ if (key === "default" || key === "__esModule") return;
+ Object.defineProperty(exports, key, {
+ enumerable: true,
+ get: function () {
+ return _DroppableEvent[key];
+ }
+ });
+});
+
+var _Droppable = __webpack_require__(34);
+
+var _Droppable2 = _interopRequireDefault(_Droppable);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _Droppable2.default;
+
+/***/ }),
+/* 37 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+/**
+ * The Emitter is a simple emitter class that provides you with `on()`, `off()` and `trigger()` methods
+ * @class Emitter
+ * @module Emitter
+ */
+class Emitter {
+ constructor() {
+ this.callbacks = {};
+ }
+
+ /**
+ * Registers callbacks by event name
+ * @param {String} type
+ * @param {...Function} callbacks
+ */
+ on(type, ...callbacks) {
+ if (!this.callbacks[type]) {
+ this.callbacks[type] = [];
+ }
+
+ this.callbacks[type].push(...callbacks);
+
+ return this;
+ }
+
+ /**
+ * Unregisters callbacks by event name
+ * @param {String} type
+ * @param {Function} callback
+ */
+ off(type, callback) {
+ if (!this.callbacks[type]) {
+ return null;
+ }
+
+ const copy = this.callbacks[type].slice(0);
+
+ for (let i = 0; i < copy.length; i++) {
+ if (callback === copy[i]) {
+ this.callbacks[type].splice(i, 1);
+ }
+ }
+
+ return this;
+ }
+
+ /**
+ * Triggers event callbacks by event object
+ * @param {AbstractEvent} event
+ */
+ trigger(event) {
+ if (!this.callbacks[event.type]) {
+ return null;
+ }
+
+ const callbacks = [...this.callbacks[event.type]];
+ const caughtErrors = [];
+
+ for (let i = callbacks.length - 1; i >= 0; i--) {
+ const callback = callbacks[i];
+
+ try {
+ callback(event);
+ } catch (error) {
+ caughtErrors.push(error);
+ }
+ }
+
+ if (caughtErrors.length) {
+ /* eslint-disable no-console */
+ console.error(`Draggable caught errors while triggering '${event.type}'`, caughtErrors);
+ /* eslint-disable no-console */
+ }
+
+ return this;
+ }
+}
+exports.default = Emitter;
+
+/***/ }),
+/* 38 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _Emitter = __webpack_require__(37);
+
+var _Emitter2 = _interopRequireDefault(_Emitter);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _Emitter2.default;
+
+/***/ }),
+/* 39 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.defaultOptions = undefined;
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _utils = __webpack_require__(2);
+
+var _Plugins = __webpack_require__(12);
+
+var _Emitter = __webpack_require__(38);
+
+var _Emitter2 = _interopRequireDefault(_Emitter);
+
+var _Sensors = __webpack_require__(6);
+
+var _DraggableEvent = __webpack_require__(13);
+
+var _DragEvent = __webpack_require__(14);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+const onDragStart = Symbol('onDragStart');
+const onDragMove = Symbol('onDragMove');
+const onDragStop = Symbol('onDragStop');
+const onDragPressure = Symbol('onDragPressure');
+
+/**
+ * @const {Object} defaultAnnouncements
+ * @const {Function} defaultAnnouncements['drag:start']
+ * @const {Function} defaultAnnouncements['drag:stop']
+ */
+const defaultAnnouncements = {
+ 'drag:start': event => `Picked up ${event.source.textContent.trim() || event.source.id || 'draggable element'}`,
+ 'drag:stop': event => `Released ${event.source.textContent.trim() || event.source.id || 'draggable element'}`
+};
+
+const defaultClasses = {
+ 'container:dragging': 'draggable-container--is-dragging',
+ 'source:dragging': 'draggable-source--is-dragging',
+ 'source:placed': 'draggable-source--placed',
+ 'container:placed': 'draggable-container--placed',
+ 'body:dragging': 'draggable--is-dragging',
+ 'draggable:over': 'draggable--over',
+ 'container:over': 'draggable-container--over',
+ 'source:original': 'draggable--original',
+ mirror: 'draggable-mirror'
+};
+
+const defaultOptions = exports.defaultOptions = {
+ draggable: '.draggable-source',
+ handle: null,
+ delay: 100,
+ distance: 0,
+ placedTimeout: 800,
+ plugins: [],
+ sensors: [],
+ exclude: {
+ plugins: [],
+ sensors: []
+ }
+};
+
+/**
+ * This is the core draggable library that does the heavy lifting
+ * @class Draggable
+ * @module Draggable
+ */
+class Draggable {
+
+ /**
+ * Draggable constructor.
+ * @constructs Draggable
+ * @param {HTMLElement[]|NodeList|HTMLElement} containers - Draggable containers
+ * @param {Object} options - Options for draggable
+ */
+
+ /**
+ * Default plugins draggable uses
+ * @static
+ * @property {Object} Plugins
+ * @property {Announcement} Plugins.Announcement
+ * @property {Focusable} Plugins.Focusable
+ * @property {Mirror} Plugins.Mirror
+ * @property {Scrollable} Plugins.Scrollable
+ * @type {Object}
+ */
+ constructor(containers = [document.body], options = {}) {
+ /**
+ * Draggable containers
+ * @property containers
+ * @type {HTMLElement[]}
+ */
+ if (containers instanceof NodeList || containers instanceof Array) {
+ this.containers = [...containers];
+ } else if (containers instanceof HTMLElement) {
+ this.containers = [containers];
+ } else {
+ throw new Error('Draggable containers are expected to be of type `NodeList`, `HTMLElement[]` or `HTMLElement`');
+ }
+
+ this.options = _extends({}, defaultOptions, options, {
+ classes: _extends({}, defaultClasses, options.classes || {}),
+ announcements: _extends({}, defaultAnnouncements, options.announcements || {}),
+ exclude: {
+ plugins: options.exclude && options.exclude.plugins || [],
+ sensors: options.exclude && options.exclude.sensors || []
+ }
+ });
+
+ /**
+ * Draggables event emitter
+ * @property emitter
+ * @type {Emitter}
+ */
+ this.emitter = new _Emitter2.default();
+
+ /**
+ * Current drag state
+ * @property dragging
+ * @type {Boolean}
+ */
+ this.dragging = false;
+
+ /**
+ * Active plugins
+ * @property plugins
+ * @type {Plugin[]}
+ */
+ this.plugins = [];
+
+ /**
+ * Active sensors
+ * @property sensors
+ * @type {Sensor[]}
+ */
+ this.sensors = [];
+
+ this[onDragStart] = this[onDragStart].bind(this);
+ this[onDragMove] = this[onDragMove].bind(this);
+ this[onDragStop] = this[onDragStop].bind(this);
+ this[onDragPressure] = this[onDragPressure].bind(this);
+
+ document.addEventListener('drag:start', this[onDragStart], true);
+ document.addEventListener('drag:move', this[onDragMove], true);
+ document.addEventListener('drag:stop', this[onDragStop], true);
+ document.addEventListener('drag:pressure', this[onDragPressure], true);
+
+ const defaultPlugins = Object.values(Draggable.Plugins).filter(Plugin => !this.options.exclude.plugins.includes(Plugin));
+ const defaultSensors = Object.values(Draggable.Sensors).filter(sensor => !this.options.exclude.sensors.includes(sensor));
+
+ this.addPlugin(...[...defaultPlugins, ...this.options.plugins]);
+ this.addSensor(...[...defaultSensors, ...this.options.sensors]);
+
+ const draggableInitializedEvent = new _DraggableEvent.DraggableInitializedEvent({
+ draggable: this
+ });
+
+ this.on('mirror:created', ({ mirror }) => this.mirror = mirror);
+ this.on('mirror:destroy', () => this.mirror = null);
+
+ this.trigger(draggableInitializedEvent);
+ }
+
+ /**
+ * Destroys Draggable instance. This removes all internal event listeners and
+ * deactivates sensors and plugins
+ */
+
+
+ /**
+ * Default sensors draggable uses
+ * @static
+ * @property {Object} Sensors
+ * @property {MouseSensor} Sensors.MouseSensor
+ * @property {TouchSensor} Sensors.TouchSensor
+ * @type {Object}
+ */
+ destroy() {
+ document.removeEventListener('drag:start', this[onDragStart], true);
+ document.removeEventListener('drag:move', this[onDragMove], true);
+ document.removeEventListener('drag:stop', this[onDragStop], true);
+ document.removeEventListener('drag:pressure', this[onDragPressure], true);
+
+ const draggableDestroyEvent = new _DraggableEvent.DraggableDestroyEvent({
+ draggable: this
+ });
+
+ this.trigger(draggableDestroyEvent);
+
+ this.removePlugin(...this.plugins.map(plugin => plugin.constructor));
+ this.removeSensor(...this.sensors.map(sensor => sensor.constructor));
+ }
+
+ /**
+ * Adds plugin to this draggable instance. This will end up calling the attach method of the plugin
+ * @param {...typeof Plugin} plugins - Plugins that you want attached to draggable
+ * @return {Draggable}
+ * @example draggable.addPlugin(CustomA11yPlugin, CustomMirrorPlugin)
+ */
+ addPlugin(...plugins) {
+ const activePlugins = plugins.map(Plugin => new Plugin(this));
+
+ activePlugins.forEach(plugin => plugin.attach());
+ this.plugins = [...this.plugins, ...activePlugins];
+
+ return this;
+ }
+
+ /**
+ * Removes plugins that are already attached to this draggable instance. This will end up calling
+ * the detach method of the plugin
+ * @param {...typeof Plugin} plugins - Plugins that you want detached from draggable
+ * @return {Draggable}
+ * @example draggable.removePlugin(MirrorPlugin, CustomMirrorPlugin)
+ */
+ removePlugin(...plugins) {
+ const removedPlugins = this.plugins.filter(plugin => plugins.includes(plugin.constructor));
+
+ removedPlugins.forEach(plugin => plugin.detach());
+ this.plugins = this.plugins.filter(plugin => !plugins.includes(plugin.constructor));
+
+ return this;
+ }
+
+ /**
+ * Adds sensors to this draggable instance. This will end up calling the attach method of the sensor
+ * @param {...typeof Sensor} sensors - Sensors that you want attached to draggable
+ * @return {Draggable}
+ * @example draggable.addSensor(ForceTouchSensor, CustomSensor)
+ */
+ addSensor(...sensors) {
+ const activeSensors = sensors.map(Sensor => new Sensor(this.containers, this.options));
+
+ activeSensors.forEach(sensor => sensor.attach());
+ this.sensors = [...this.sensors, ...activeSensors];
+
+ return this;
+ }
+
+ /**
+ * Removes sensors that are already attached to this draggable instance. This will end up calling
+ * the detach method of the sensor
+ * @param {...typeof Sensor} sensors - Sensors that you want attached to draggable
+ * @return {Draggable}
+ * @example draggable.removeSensor(TouchSensor, DragSensor)
+ */
+ removeSensor(...sensors) {
+ const removedSensors = this.sensors.filter(sensor => sensors.includes(sensor.constructor));
+
+ removedSensors.forEach(sensor => sensor.detach());
+ this.sensors = this.sensors.filter(sensor => !sensors.includes(sensor.constructor));
+
+ return this;
+ }
+
+ /**
+ * Adds container to this draggable instance
+ * @param {...HTMLElement} containers - Containers you want to add to draggable
+ * @return {Draggable}
+ * @example draggable.addContainer(document.body)
+ */
+ addContainer(...containers) {
+ this.containers = [...this.containers, ...containers];
+ this.sensors.forEach(sensor => sensor.addContainer(...containers));
+ return this;
+ }
+
+ /**
+ * Removes container from this draggable instance
+ * @param {...HTMLElement} containers - Containers you want to remove from draggable
+ * @return {Draggable}
+ * @example draggable.removeContainer(document.body)
+ */
+ removeContainer(...containers) {
+ this.containers = this.containers.filter(container => !containers.includes(container));
+ this.sensors.forEach(sensor => sensor.removeContainer(...containers));
+ return this;
+ }
+
+ /**
+ * Adds listener for draggable events
+ * @param {String} type - Event name
+ * @param {...Function} callbacks - Event callbacks
+ * @return {Draggable}
+ * @example draggable.on('drag:start', (dragEvent) => dragEvent.cancel());
+ */
+ on(type, ...callbacks) {
+ this.emitter.on(type, ...callbacks);
+ return this;
+ }
+
+ /**
+ * Removes listener from draggable
+ * @param {String} type - Event name
+ * @param {Function} callback - Event callback
+ * @return {Draggable}
+ * @example draggable.off('drag:start', handlerFunction);
+ */
+ off(type, callback) {
+ this.emitter.off(type, callback);
+ return this;
+ }
+
+ /**
+ * Triggers draggable event
+ * @param {AbstractEvent} event - Event instance
+ * @return {Draggable}
+ * @example draggable.trigger(event);
+ */
+ trigger(event) {
+ this.emitter.trigger(event);
+ return this;
+ }
+
+ /**
+ * Returns class name for class identifier
+ * @param {String} name - Name of class identifier
+ * @return {String|null}
+ */
+ getClassNameFor(name) {
+ return this.options.classes[name];
+ }
+
+ /**
+ * Returns true if this draggable instance is currently dragging
+ * @return {Boolean}
+ */
+ isDragging() {
+ return Boolean(this.dragging);
+ }
+
+ /**
+ * Returns all draggable elements
+ * @return {HTMLElement[]}
+ */
+ getDraggableElements() {
+ return this.containers.reduce((current, container) => {
+ return [...current, ...this.getDraggableElementsForContainer(container)];
+ }, []);
+ }
+
+ /**
+ * Returns draggable elements for a given container, excluding the mirror and
+ * original source element if present
+ * @param {HTMLElement} container
+ * @return {HTMLElement[]}
+ */
+ getDraggableElementsForContainer(container) {
+ const allDraggableElements = container.querySelectorAll(this.options.draggable);
+
+ return [...allDraggableElements].filter(childElement => {
+ return childElement !== this.originalSource && childElement !== this.mirror;
+ });
+ }
+
+ /**
+ * Drag start handler
+ * @private
+ * @param {Event} event - DOM Drag event
+ */
+ [onDragStart](event) {
+ const sensorEvent = getSensorEvent(event);
+ const { target, container } = sensorEvent;
+
+ if (!this.containers.includes(container)) {
+ return;
+ }
+
+ if (this.options.handle && target && !(0, _utils.closest)(target, this.options.handle)) {
+ sensorEvent.cancel();
+ return;
+ }
+
+ // Find draggable source element
+ this.originalSource = (0, _utils.closest)(target, this.options.draggable);
+ this.sourceContainer = container;
+
+ if (!this.originalSource) {
+ sensorEvent.cancel();
+ return;
+ }
+
+ if (this.lastPlacedSource && this.lastPlacedContainer) {
+ clearTimeout(this.placedTimeoutID);
+ this.lastPlacedSource.classList.remove(this.getClassNameFor('source:placed'));
+ this.lastPlacedContainer.classList.remove(this.getClassNameFor('container:placed'));
+ }
+
+ this.source = this.originalSource.cloneNode(true);
+ this.originalSource.parentNode.insertBefore(this.source, this.originalSource);
+ this.originalSource.style.display = 'none';
+
+ const dragEvent = new _DragEvent.DragStartEvent({
+ source: this.source,
+ originalSource: this.originalSource,
+ sourceContainer: container,
+ sensorEvent
+ });
+
+ this.trigger(dragEvent);
+
+ this.dragging = !dragEvent.canceled();
+
+ if (dragEvent.canceled()) {
+ this.source.parentNode.removeChild(this.source);
+ this.originalSource.style.display = null;
+ return;
+ }
+
+ this.originalSource.classList.add(this.getClassNameFor('source:original'));
+ this.source.classList.add(this.getClassNameFor('source:dragging'));
+ this.sourceContainer.classList.add(this.getClassNameFor('container:dragging'));
+ document.body.classList.add(this.getClassNameFor('body:dragging'));
+ applyUserSelect(document.body, 'none');
+
+ requestAnimationFrame(() => {
+ const oldSensorEvent = getSensorEvent(event);
+ const newSensorEvent = oldSensorEvent.clone({ target: this.source });
+
+ this[onDragMove](_extends({}, event, {
+ detail: newSensorEvent
+ }));
+ });
+ }
+
+ /**
+ * Drag move handler
+ * @private
+ * @param {Event} event - DOM Drag event
+ */
+ [onDragMove](event) {
+ if (!this.dragging) {
+ return;
+ }
+
+ const sensorEvent = getSensorEvent(event);
+ const { container } = sensorEvent;
+ let target = sensorEvent.target;
+
+ const dragMoveEvent = new _DragEvent.DragMoveEvent({
+ source: this.source,
+ originalSource: this.originalSource,
+ sourceContainer: container,
+ sensorEvent
+ });
+
+ this.trigger(dragMoveEvent);
+
+ if (dragMoveEvent.canceled()) {
+ sensorEvent.cancel();
+ }
+
+ target = (0, _utils.closest)(target, this.options.draggable);
+ const withinCorrectContainer = (0, _utils.closest)(sensorEvent.target, this.containers);
+ const overContainer = sensorEvent.overContainer || withinCorrectContainer;
+ const isLeavingContainer = this.currentOverContainer && overContainer !== this.currentOverContainer;
+ const isLeavingDraggable = this.currentOver && target !== this.currentOver;
+ const isOverContainer = overContainer && this.currentOverContainer !== overContainer;
+ const isOverDraggable = withinCorrectContainer && target && this.currentOver !== target;
+
+ if (isLeavingDraggable) {
+ const dragOutEvent = new _DragEvent.DragOutEvent({
+ source: this.source,
+ originalSource: this.originalSource,
+ sourceContainer: container,
+ sensorEvent,
+ over: this.currentOver
+ });
+
+ this.currentOver.classList.remove(this.getClassNameFor('draggable:over'));
+ this.currentOver = null;
+
+ this.trigger(dragOutEvent);
+ }
+
+ if (isLeavingContainer) {
+ const dragOutContainerEvent = new _DragEvent.DragOutContainerEvent({
+ source: this.source,
+ originalSource: this.originalSource,
+ sourceContainer: container,
+ sensorEvent,
+ overContainer: this.currentOverContainer
+ });
+
+ this.currentOverContainer.classList.remove(this.getClassNameFor('container:over'));
+ this.currentOverContainer = null;
+
+ this.trigger(dragOutContainerEvent);
+ }
+
+ if (isOverContainer) {
+ overContainer.classList.add(this.getClassNameFor('container:over'));
+
+ const dragOverContainerEvent = new _DragEvent.DragOverContainerEvent({
+ source: this.source,
+ originalSource: this.originalSource,
+ sourceContainer: container,
+ sensorEvent,
+ overContainer
+ });
+
+ this.currentOverContainer = overContainer;
+
+ this.trigger(dragOverContainerEvent);
+ }
+
+ if (isOverDraggable) {
+ target.classList.add(this.getClassNameFor('draggable:over'));
+
+ const dragOverEvent = new _DragEvent.DragOverEvent({
+ source: this.source,
+ originalSource: this.originalSource,
+ sourceContainer: container,
+ sensorEvent,
+ overContainer,
+ over: target
+ });
+
+ this.currentOver = target;
+
+ this.trigger(dragOverEvent);
+ }
+ }
+
+ /**
+ * Drag stop handler
+ * @private
+ * @param {Event} event - DOM Drag event
+ */
+ [onDragStop](event) {
+ if (!this.dragging) {
+ return;
+ }
+
+ this.dragging = false;
+
+ const dragStopEvent = new _DragEvent.DragStopEvent({
+ source: this.source,
+ originalSource: this.originalSource,
+ sensorEvent: event.sensorEvent,
+ sourceContainer: this.sourceContainer
+ });
+
+ this.trigger(dragStopEvent);
+
+ this.source.parentNode.insertBefore(this.originalSource, this.source);
+ this.source.parentNode.removeChild(this.source);
+ this.originalSource.style.display = '';
+
+ this.source.classList.remove(this.getClassNameFor('source:dragging'));
+ this.originalSource.classList.remove(this.getClassNameFor('source:original'));
+ this.originalSource.classList.add(this.getClassNameFor('source:placed'));
+ this.sourceContainer.classList.add(this.getClassNameFor('container:placed'));
+ this.sourceContainer.classList.remove(this.getClassNameFor('container:dragging'));
+ document.body.classList.remove(this.getClassNameFor('body:dragging'));
+ applyUserSelect(document.body, '');
+
+ if (this.currentOver) {
+ this.currentOver.classList.remove(this.getClassNameFor('draggable:over'));
+ }
+
+ if (this.currentOverContainer) {
+ this.currentOverContainer.classList.remove(this.getClassNameFor('container:over'));
+ }
+
+ this.lastPlacedSource = this.originalSource;
+ this.lastPlacedContainer = this.sourceContainer;
+
+ this.placedTimeoutID = setTimeout(() => {
+ if (this.lastPlacedSource) {
+ this.lastPlacedSource.classList.remove(this.getClassNameFor('source:placed'));
+ }
+
+ if (this.lastPlacedContainer) {
+ this.lastPlacedContainer.classList.remove(this.getClassNameFor('container:placed'));
+ }
+
+ this.lastPlacedSource = null;
+ this.lastPlacedContainer = null;
+ }, this.options.placedTimeout);
+
+ this.source = null;
+ this.originalSource = null;
+ this.currentOverContainer = null;
+ this.currentOver = null;
+ this.sourceContainer = null;
+ }
+
+ /**
+ * Drag pressure handler
+ * @private
+ * @param {Event} event - DOM Drag event
+ */
+ [onDragPressure](event) {
+ if (!this.dragging) {
+ return;
+ }
+
+ const sensorEvent = getSensorEvent(event);
+ const source = this.source || (0, _utils.closest)(sensorEvent.originalEvent.target, this.options.draggable);
+
+ const dragPressureEvent = new _DragEvent.DragPressureEvent({
+ sensorEvent,
+ source,
+ pressure: sensorEvent.pressure
+ });
+
+ this.trigger(dragPressureEvent);
+ }
+}
+
+exports.default = Draggable;
+Draggable.Plugins = { Announcement: _Plugins.Announcement, Focusable: _Plugins.Focusable, Mirror: _Plugins.Mirror, Scrollable: _Plugins.Scrollable };
+Draggable.Sensors = { MouseSensor: _Sensors.MouseSensor, TouchSensor: _Sensors.TouchSensor };
+function getSensorEvent(event) {
+ return event.detail;
+}
+
+function applyUserSelect(element, value) {
+ element.style.webkitUserSelect = value;
+ element.style.mozUserSelect = value;
+ element.style.msUserSelect = value;
+ element.style.oUserSelect = value;
+ element.style.userSelect = value;
+}
+
+/***/ }),
+/* 40 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _Sensor = __webpack_require__(4);
+
+var _Sensor2 = _interopRequireDefault(_Sensor);
+
+var _SensorEvent = __webpack_require__(3);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+const onMouseForceWillBegin = Symbol('onMouseForceWillBegin');
+const onMouseForceDown = Symbol('onMouseForceDown');
+const onMouseDown = Symbol('onMouseDown');
+const onMouseForceChange = Symbol('onMouseForceChange');
+const onMouseMove = Symbol('onMouseMove');
+const onMouseUp = Symbol('onMouseUp');
+const onMouseForceGlobalChange = Symbol('onMouseForceGlobalChange');
+
+/**
+ * This sensor picks up native force touch events and dictates drag operations
+ * @class ForceTouchSensor
+ * @module ForceTouchSensor
+ * @extends Sensor
+ */
+class ForceTouchSensor extends _Sensor2.default {
+ /**
+ * ForceTouchSensor constructor.
+ * @constructs ForceTouchSensor
+ * @param {HTMLElement[]|NodeList|HTMLElement} containers - Containers
+ * @param {Object} options - Options
+ */
+ constructor(containers = [], options = {}) {
+ super(containers, options);
+
+ /**
+ * Draggable element needs to be remembered to unset the draggable attribute after drag operation has completed
+ * @property mightDrag
+ * @type {Boolean}
+ */
+ this.mightDrag = false;
+
+ this[onMouseForceWillBegin] = this[onMouseForceWillBegin].bind(this);
+ this[onMouseForceDown] = this[onMouseForceDown].bind(this);
+ this[onMouseDown] = this[onMouseDown].bind(this);
+ this[onMouseForceChange] = this[onMouseForceChange].bind(this);
+ this[onMouseMove] = this[onMouseMove].bind(this);
+ this[onMouseUp] = this[onMouseUp].bind(this);
+ }
+
+ /**
+ * Attaches sensors event listeners to the DOM
+ */
+ attach() {
+ for (const container of this.containers) {
+ container.addEventListener('webkitmouseforcewillbegin', this[onMouseForceWillBegin], false);
+ container.addEventListener('webkitmouseforcedown', this[onMouseForceDown], false);
+ container.addEventListener('mousedown', this[onMouseDown], true);
+ container.addEventListener('webkitmouseforcechanged', this[onMouseForceChange], false);
+ }
+
+ document.addEventListener('mousemove', this[onMouseMove]);
+ document.addEventListener('mouseup', this[onMouseUp]);
+ }
+
+ /**
+ * Detaches sensors event listeners to the DOM
+ */
+ detach() {
+ for (const container of this.containers) {
+ container.removeEventListener('webkitmouseforcewillbegin', this[onMouseForceWillBegin], false);
+ container.removeEventListener('webkitmouseforcedown', this[onMouseForceDown], false);
+ container.removeEventListener('mousedown', this[onMouseDown], true);
+ container.removeEventListener('webkitmouseforcechanged', this[onMouseForceChange], false);
+ }
+
+ document.removeEventListener('mousemove', this[onMouseMove]);
+ document.removeEventListener('mouseup', this[onMouseUp]);
+ }
+
+ /**
+ * Mouse force will begin handler
+ * @private
+ * @param {Event} event - Mouse force will begin event
+ */
+ [onMouseForceWillBegin](event) {
+ event.preventDefault();
+ this.mightDrag = true;
+ }
+
+ /**
+ * Mouse force down handler
+ * @private
+ * @param {Event} event - Mouse force down event
+ */
+ [onMouseForceDown](event) {
+ if (this.dragging) {
+ return;
+ }
+
+ const target = document.elementFromPoint(event.clientX, event.clientY);
+ const container = event.currentTarget;
+
+ const dragStartEvent = new _SensorEvent.DragStartSensorEvent({
+ clientX: event.clientX,
+ clientY: event.clientY,
+ target,
+ container,
+ originalEvent: event
+ });
+
+ this.trigger(container, dragStartEvent);
+
+ this.currentContainer = container;
+ this.dragging = !dragStartEvent.canceled();
+ this.mightDrag = false;
+ }
+
+ /**
+ * Mouse up handler
+ * @private
+ * @param {Event} event - Mouse up event
+ */
+ [onMouseUp](event) {
+ if (!this.dragging) {
+ return;
+ }
+
+ const dragStopEvent = new _SensorEvent.DragStopSensorEvent({
+ clientX: event.clientX,
+ clientY: event.clientY,
+ target: null,
+ container: this.currentContainer,
+ originalEvent: event
+ });
+
+ this.trigger(this.currentContainer, dragStopEvent);
+
+ this.currentContainer = null;
+ this.dragging = false;
+ this.mightDrag = false;
+ }
+
+ /**
+ * Mouse down handler
+ * @private
+ * @param {Event} event - Mouse down event
+ */
+ [onMouseDown](event) {
+ if (!this.mightDrag) {
+ return;
+ }
+
+ // Need workaround for real click
+ // Cancel potential drag events
+ event.stopPropagation();
+ event.stopImmediatePropagation();
+ event.preventDefault();
+ }
+
+ /**
+ * Mouse move handler
+ * @private
+ * @param {Event} event - Mouse force will begin event
+ */
+ [onMouseMove](event) {
+ if (!this.dragging) {
+ return;
+ }
+
+ const target = document.elementFromPoint(event.clientX, event.clientY);
+
+ const dragMoveEvent = new _SensorEvent.DragMoveSensorEvent({
+ clientX: event.clientX,
+ clientY: event.clientY,
+ target,
+ container: this.currentContainer,
+ originalEvent: event
+ });
+
+ this.trigger(this.currentContainer, dragMoveEvent);
+ }
+
+ /**
+ * Mouse force change handler
+ * @private
+ * @param {Event} event - Mouse force change event
+ */
+ [onMouseForceChange](event) {
+ if (this.dragging) {
+ return;
+ }
+
+ const target = event.target;
+ const container = event.currentTarget;
+
+ const dragPressureEvent = new _SensorEvent.DragPressureSensorEvent({
+ pressure: event.webkitForce,
+ clientX: event.clientX,
+ clientY: event.clientY,
+ target,
+ container,
+ originalEvent: event
+ });
+
+ this.trigger(container, dragPressureEvent);
+ }
+
+ /**
+ * Mouse force global change handler
+ * @private
+ * @param {Event} event - Mouse force global change event
+ */
+ [onMouseForceGlobalChange](event) {
+ if (!this.dragging) {
+ return;
+ }
+
+ const target = event.target;
+
+ const dragPressureEvent = new _SensorEvent.DragPressureSensorEvent({
+ pressure: event.webkitForce,
+ clientX: event.clientX,
+ clientY: event.clientY,
+ target,
+ container: this.currentContainer,
+ originalEvent: event
+ });
+
+ this.trigger(this.currentContainer, dragPressureEvent);
+ }
+}
+exports.default = ForceTouchSensor;
+
+/***/ }),
+/* 41 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _ForceTouchSensor = __webpack_require__(40);
+
+var _ForceTouchSensor2 = _interopRequireDefault(_ForceTouchSensor);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _ForceTouchSensor2.default;
+
+/***/ }),
+/* 42 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _utils = __webpack_require__(2);
+
+var _Sensor = __webpack_require__(4);
+
+var _Sensor2 = _interopRequireDefault(_Sensor);
+
+var _SensorEvent = __webpack_require__(3);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+const onMouseDown = Symbol('onMouseDown');
+const onMouseUp = Symbol('onMouseUp');
+const onDragStart = Symbol('onDragStart');
+const onDragOver = Symbol('onDragOver');
+const onDragEnd = Symbol('onDragEnd');
+const onDrop = Symbol('onDrop');
+const reset = Symbol('reset');
+
+/**
+ * This sensor picks up native browser drag events and dictates drag operations
+ * @class DragSensor
+ * @module DragSensor
+ * @extends Sensor
+ */
+class DragSensor extends _Sensor2.default {
+ /**
+ * DragSensor constructor.
+ * @constructs DragSensor
+ * @param {HTMLElement[]|NodeList|HTMLElement} containers - Containers
+ * @param {Object} options - Options
+ */
+ constructor(containers = [], options = {}) {
+ super(containers, options);
+
+ /**
+ * Mouse down timer which will end up setting the draggable attribute, unless canceled
+ * @property mouseDownTimeout
+ * @type {Number}
+ */
+ this.mouseDownTimeout = null;
+
+ /**
+ * Draggable element needs to be remembered to unset the draggable attribute after drag operation has completed
+ * @property draggableElement
+ * @type {HTMLElement}
+ */
+ this.draggableElement = null;
+
+ /**
+ * Native draggable element could be links or images, their draggable state will be disabled during drag operation
+ * @property nativeDraggableElement
+ * @type {HTMLElement}
+ */
+ this.nativeDraggableElement = null;
+
+ this[onMouseDown] = this[onMouseDown].bind(this);
+ this[onMouseUp] = this[onMouseUp].bind(this);
+ this[onDragStart] = this[onDragStart].bind(this);
+ this[onDragOver] = this[onDragOver].bind(this);
+ this[onDragEnd] = this[onDragEnd].bind(this);
+ this[onDrop] = this[onDrop].bind(this);
+ }
+
+ /**
+ * Attaches sensors event listeners to the DOM
+ */
+ attach() {
+ document.addEventListener('mousedown', this[onMouseDown], true);
+ }
+
+ /**
+ * Detaches sensors event listeners to the DOM
+ */
+ detach() {
+ document.removeEventListener('mousedown', this[onMouseDown], true);
+ }
+
+ /**
+ * Drag start handler
+ * @private
+ * @param {Event} event - Drag start event
+ */
+ [onDragStart](event) {
+ // Need for firefox. "text" key is needed for IE
+ event.dataTransfer.setData('text', '');
+ event.dataTransfer.effectAllowed = this.options.type;
+
+ const target = document.elementFromPoint(event.clientX, event.clientY);
+ this.currentContainer = (0, _utils.closest)(event.target, this.containers);
+
+ if (!this.currentContainer) {
+ return;
+ }
+
+ const dragStartEvent = new _SensorEvent.DragStartSensorEvent({
+ clientX: event.clientX,
+ clientY: event.clientY,
+ target,
+ container: this.currentContainer,
+ originalEvent: event
+ });
+
+ // Workaround
+ setTimeout(() => {
+ this.trigger(this.currentContainer, dragStartEvent);
+
+ if (dragStartEvent.canceled()) {
+ this.dragging = false;
+ } else {
+ this.dragging = true;
+ }
+ }, 0);
+ }
+
+ /**
+ * Drag over handler
+ * @private
+ * @param {Event} event - Drag over event
+ */
+ [onDragOver](event) {
+ if (!this.dragging) {
+ return;
+ }
+
+ const target = document.elementFromPoint(event.clientX, event.clientY);
+ const container = this.currentContainer;
+
+ const dragMoveEvent = new _SensorEvent.DragMoveSensorEvent({
+ clientX: event.clientX,
+ clientY: event.clientY,
+ target,
+ container,
+ originalEvent: event
+ });
+
+ this.trigger(container, dragMoveEvent);
+
+ if (!dragMoveEvent.canceled()) {
+ event.preventDefault();
+ event.dataTransfer.dropEffect = this.options.type;
+ }
+ }
+
+ /**
+ * Drag end handler
+ * @private
+ * @param {Event} event - Drag end event
+ */
+ [onDragEnd](event) {
+ if (!this.dragging) {
+ return;
+ }
+
+ document.removeEventListener('mouseup', this[onMouseUp], true);
+
+ const target = document.elementFromPoint(event.clientX, event.clientY);
+ const container = this.currentContainer;
+
+ const dragStopEvent = new _SensorEvent.DragStopSensorEvent({
+ clientX: event.clientX,
+ clientY: event.clientY,
+ target,
+ container,
+ originalEvent: event
+ });
+
+ this.trigger(container, dragStopEvent);
+
+ this.dragging = false;
+ this.startEvent = null;
+
+ this[reset]();
+ }
+
+ /**
+ * Drop handler
+ * @private
+ * @param {Event} event - Drop event
+ */
+ [onDrop](event) {
+ // eslint-disable-line class-methods-use-this
+ event.preventDefault();
+ }
+
+ /**
+ * Mouse down handler
+ * @private
+ * @param {Event} event - Mouse down event
+ */
+ [onMouseDown](event) {
+ // Firefox bug for inputs within draggables https://bugzilla.mozilla.org/show_bug.cgi?id=739071
+ if (event.target && (event.target.form || event.target.contenteditable)) {
+ return;
+ }
+
+ const nativeDraggableElement = (0, _utils.closest)(event.target, element => element.draggable);
+
+ if (nativeDraggableElement) {
+ nativeDraggableElement.draggable = false;
+ this.nativeDraggableElement = nativeDraggableElement;
+ }
+
+ document.addEventListener('mouseup', this[onMouseUp], true);
+ document.addEventListener('dragstart', this[onDragStart], false);
+ document.addEventListener('dragover', this[onDragOver], false);
+ document.addEventListener('dragend', this[onDragEnd], false);
+ document.addEventListener('drop', this[onDrop], false);
+
+ const target = (0, _utils.closest)(event.target, this.options.draggable);
+
+ if (!target) {
+ return;
+ }
+
+ this.startEvent = event;
+
+ this.mouseDownTimeout = setTimeout(() => {
+ target.draggable = true;
+ this.draggableElement = target;
+ }, this.options.delay);
+ }
+
+ /**
+ * Mouse up handler
+ * @private
+ * @param {Event} event - Mouse up event
+ */
+ [onMouseUp]() {
+ this[reset]();
+ }
+
+ /**
+ * Mouse up handler
+ * @private
+ * @param {Event} event - Mouse up event
+ */
+ [reset]() {
+ clearTimeout(this.mouseDownTimeout);
+
+ document.removeEventListener('mouseup', this[onMouseUp], true);
+ document.removeEventListener('dragstart', this[onDragStart], false);
+ document.removeEventListener('dragover', this[onDragOver], false);
+ document.removeEventListener('dragend', this[onDragEnd], false);
+ document.removeEventListener('drop', this[onDrop], false);
+
+ if (this.nativeDraggableElement) {
+ this.nativeDraggableElement.draggable = true;
+ this.nativeDraggableElement = null;
+ }
+
+ if (this.draggableElement) {
+ this.draggableElement.draggable = false;
+ this.draggableElement = null;
+ }
+ }
+}
+exports.default = DragSensor;
+
+/***/ }),
+/* 43 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _DragSensor = __webpack_require__(42);
+
+var _DragSensor2 = _interopRequireDefault(_DragSensor);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _DragSensor2.default;
+
+/***/ }),
+/* 44 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _utils = __webpack_require__(2);
+
+var _Sensor = __webpack_require__(4);
+
+var _Sensor2 = _interopRequireDefault(_Sensor);
+
+var _SensorEvent = __webpack_require__(3);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+const onTouchStart = Symbol('onTouchStart');
+const onTouchEnd = Symbol('onTouchEnd');
+const onTouchMove = Symbol('onTouchMove');
+const startDrag = Symbol('startDrag');
+const onDistanceChange = Symbol('onDistanceChange');
+
+/**
+ * Prevents scrolling when set to true
+ * @var {Boolean} preventScrolling
+ */
+let preventScrolling = false;
+
+// WebKit requires cancelable `touchmove` events to be added as early as possible
+window.addEventListener('touchmove', event => {
+ if (!preventScrolling) {
+ return;
+ }
+
+ // Prevent scrolling
+ event.preventDefault();
+}, { passive: false });
+
+/**
+ * This sensor picks up native browser touch events and dictates drag operations
+ * @class TouchSensor
+ * @module TouchSensor
+ * @extends Sensor
+ */
+class TouchSensor extends _Sensor2.default {
+ /**
+ * TouchSensor constructor.
+ * @constructs TouchSensor
+ * @param {HTMLElement[]|NodeList|HTMLElement} containers - Containers
+ * @param {Object} options - Options
+ */
+ constructor(containers = [], options = {}) {
+ super(containers, options);
+
+ /**
+ * Closest scrollable container so accidental scroll can cancel long touch
+ * @property currentScrollableParent
+ * @type {HTMLElement}
+ */
+ this.currentScrollableParent = null;
+
+ /**
+ * TimeoutID for managing delay
+ * @property tapTimeout
+ * @type {Number}
+ */
+ this.tapTimeout = null;
+
+ /**
+ * touchMoved indicates if touch has moved during tapTimeout
+ * @property touchMoved
+ * @type {Boolean}
+ */
+ this.touchMoved = false;
+
+ this[onTouchStart] = this[onTouchStart].bind(this);
+ this[onTouchEnd] = this[onTouchEnd].bind(this);
+ this[onTouchMove] = this[onTouchMove].bind(this);
+ this[startDrag] = this[startDrag].bind(this);
+ this[onDistanceChange] = this[onDistanceChange].bind(this);
+ }
+
+ /**
+ * Attaches sensors event listeners to the DOM
+ */
+ attach() {
+ document.addEventListener('touchstart', this[onTouchStart]);
+ }
+
+ /**
+ * Detaches sensors event listeners to the DOM
+ */
+ detach() {
+ document.removeEventListener('touchstart', this[onTouchStart]);
+ }
+
+ /**
+ * Touch start handler
+ * @private
+ * @param {Event} event - Touch start event
+ */
+ [onTouchStart](event) {
+ const container = (0, _utils.closest)(event.target, this.containers);
+
+ if (!container) {
+ return;
+ }
+ const { distance = 0, delay = 0 } = this.options;
+ const { pageX, pageY } = (0, _utils.touchCoords)(event);
+
+ Object.assign(this, { pageX, pageY });
+ this.onTouchStartAt = Date.now();
+ this.startEvent = event;
+ this.currentContainer = container;
+
+ document.addEventListener('touchend', this[onTouchEnd]);
+ document.addEventListener('touchcancel', this[onTouchEnd]);
+ document.addEventListener('touchmove', this[onDistanceChange]);
+ container.addEventListener('contextmenu', onContextMenu);
+
+ if (distance) {
+ preventScrolling = true;
+ }
+
+ this.tapTimeout = window.setTimeout(() => {
+ this[onDistanceChange]({ touches: [{ pageX: this.pageX, pageY: this.pageY }] });
+ }, delay);
+ }
+
+ /**
+ * Start the drag
+ * @private
+ */
+ [startDrag]() {
+ const startEvent = this.startEvent;
+ const container = this.currentContainer;
+ const touch = (0, _utils.touchCoords)(startEvent);
+
+ const dragStartEvent = new _SensorEvent.DragStartSensorEvent({
+ clientX: touch.pageX,
+ clientY: touch.pageY,
+ target: startEvent.target,
+ container,
+ originalEvent: startEvent
+ });
+
+ this.trigger(this.currentContainer, dragStartEvent);
+
+ this.dragging = !dragStartEvent.canceled();
+
+ if (this.dragging) {
+ document.addEventListener('touchmove', this[onTouchMove]);
+ }
+ preventScrolling = this.dragging;
+ }
+
+ /**
+ * Touch move handler prior to drag start.
+ * @private
+ * @param {Event} event - Touch move event
+ */
+ [onDistanceChange](event) {
+ const { delay, distance } = this.options;
+ const { startEvent } = this;
+ const start = (0, _utils.touchCoords)(startEvent);
+ const current = (0, _utils.touchCoords)(event);
+ const timeElapsed = Date.now() - this.onTouchStartAt;
+ const distanceTravelled = (0, _utils.distance)(start.pageX, start.pageY, current.pageX, current.pageY);
+
+ Object.assign(this, current);
+ if (timeElapsed >= delay && distanceTravelled >= distance) {
+ window.clearTimeout(this.tapTimeout);
+ document.removeEventListener('touchmove', this[onDistanceChange]);
+ this[startDrag]();
+ }
+ }
+
+ /**
+ * Mouse move handler while dragging
+ * @private
+ * @param {Event} event - Touch move event
+ */
+ [onTouchMove](event) {
+ if (!this.dragging) {
+ return;
+ }
+ const { pageX, pageY } = (0, _utils.touchCoords)(event);
+ const target = document.elementFromPoint(pageX - window.scrollX, pageY - window.scrollY);
+
+ const dragMoveEvent = new _SensorEvent.DragMoveSensorEvent({
+ clientX: pageX,
+ clientY: pageY,
+ target,
+ container: this.currentContainer,
+ originalEvent: event
+ });
+
+ this.trigger(this.currentContainer, dragMoveEvent);
+ }
+
+ /**
+ * Touch end handler
+ * @private
+ * @param {Event} event - Touch end event
+ */
+ [onTouchEnd](event) {
+ clearTimeout(this.tapTimeout);
+ preventScrolling = false;
+
+ document.removeEventListener('touchend', this[onTouchEnd]);
+ document.removeEventListener('touchcancel', this[onTouchEnd]);
+ document.removeEventListener('touchmove', this[onDistanceChange]);
+
+ if (this.currentContainer) {
+ this.currentContainer.removeEventListener('contextmenu', onContextMenu);
+ }
+
+ if (!this.dragging) {
+ return;
+ }
+
+ document.removeEventListener('touchmove', this[onTouchMove]);
+
+ const { pageX, pageY } = (0, _utils.touchCoords)(event);
+ const target = document.elementFromPoint(pageX - window.scrollX, pageY - window.scrollY);
+
+ event.preventDefault();
+
+ const dragStopEvent = new _SensorEvent.DragStopSensorEvent({
+ clientX: pageX,
+ clientY: pageY,
+ target,
+ container: this.currentContainer,
+ originalEvent: event
+ });
+
+ this.trigger(this.currentContainer, dragStopEvent);
+
+ this.currentContainer = null;
+ this.dragging = false;
+ this.startEvent = null;
+ }
+}
+
+exports.default = TouchSensor;
+function onContextMenu(event) {
+ event.preventDefault();
+ event.stopPropagation();
+}
+
+/***/ }),
+/* 45 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _TouchSensor = __webpack_require__(44);
+
+var _TouchSensor2 = _interopRequireDefault(_TouchSensor);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _TouchSensor2.default;
+
+/***/ }),
+/* 46 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.DragPressureSensorEvent = exports.DragStopSensorEvent = exports.DragMoveSensorEvent = exports.DragStartSensorEvent = exports.SensorEvent = undefined;
+
+var _AbstractEvent = __webpack_require__(1);
+
+var _AbstractEvent2 = _interopRequireDefault(_AbstractEvent);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/**
+ * Base sensor event
+ * @class SensorEvent
+ * @module SensorEvent
+ * @extends AbstractEvent
+ */
+class SensorEvent extends _AbstractEvent2.default {
+ /**
+ * Original browser event that triggered a sensor
+ * @property originalEvent
+ * @type {Event}
+ * @readonly
+ */
+ get originalEvent() {
+ return this.data.originalEvent;
+ }
+
+ /**
+ * Normalized clientX for both touch and mouse events
+ * @property clientX
+ * @type {Number}
+ * @readonly
+ */
+ get clientX() {
+ return this.data.clientX;
+ }
+
+ /**
+ * Normalized clientY for both touch and mouse events
+ * @property clientY
+ * @type {Number}
+ * @readonly
+ */
+ get clientY() {
+ return this.data.clientY;
+ }
+
+ /**
+ * Normalized target for both touch and mouse events
+ * Returns the element that is behind cursor or touch pointer
+ * @property target
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get target() {
+ return this.data.target;
+ }
+
+ /**
+ * Container that initiated the sensor
+ * @property container
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get container() {
+ return this.data.container;
+ }
+
+ /**
+ * Trackpad pressure
+ * @property pressure
+ * @type {Number}
+ * @readonly
+ */
+ get pressure() {
+ return this.data.pressure;
+ }
+}
+
+exports.SensorEvent = SensorEvent; /**
+ * Drag start sensor event
+ * @class DragStartSensorEvent
+ * @module DragStartSensorEvent
+ * @extends SensorEvent
+ */
+
+class DragStartSensorEvent extends SensorEvent {}
+
+exports.DragStartSensorEvent = DragStartSensorEvent; /**
+ * Drag move sensor event
+ * @class DragMoveSensorEvent
+ * @module DragMoveSensorEvent
+ * @extends SensorEvent
+ */
+
+DragStartSensorEvent.type = 'drag:start';
+class DragMoveSensorEvent extends SensorEvent {}
+
+exports.DragMoveSensorEvent = DragMoveSensorEvent; /**
+ * Drag stop sensor event
+ * @class DragStopSensorEvent
+ * @module DragStopSensorEvent
+ * @extends SensorEvent
+ */
+
+DragMoveSensorEvent.type = 'drag:move';
+class DragStopSensorEvent extends SensorEvent {}
+
+exports.DragStopSensorEvent = DragStopSensorEvent; /**
+ * Drag pressure sensor event
+ * @class DragPressureSensorEvent
+ * @module DragPressureSensorEvent
+ * @extends SensorEvent
+ */
+
+DragStopSensorEvent.type = 'drag:stop';
+class DragPressureSensorEvent extends SensorEvent {}
+exports.DragPressureSensorEvent = DragPressureSensorEvent;
+DragPressureSensorEvent.type = 'drag:pressure';
+
+/***/ }),
+/* 47 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _utils = __webpack_require__(2);
+
+var _Sensor = __webpack_require__(4);
+
+var _Sensor2 = _interopRequireDefault(_Sensor);
+
+var _SensorEvent = __webpack_require__(3);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+const onContextMenuWhileDragging = Symbol('onContextMenuWhileDragging');
+const onMouseDown = Symbol('onMouseDown');
+const onMouseMove = Symbol('onMouseMove');
+const onMouseUp = Symbol('onMouseUp');
+const startDrag = Symbol('startDrag');
+const onDistanceChange = Symbol('onDistanceChange');
+
+/**
+ * This sensor picks up native browser mouse events and dictates drag operations
+ * @class MouseSensor
+ * @module MouseSensor
+ * @extends Sensor
+ */
+class MouseSensor extends _Sensor2.default {
+ /**
+ * MouseSensor constructor.
+ * @constructs MouseSensor
+ * @param {HTMLElement[]|NodeList|HTMLElement} containers - Containers
+ * @param {Object} options - Options
+ */
+ constructor(containers = [], options = {}) {
+ super(containers, options);
+
+ /**
+ * Mouse down timer which will end up triggering the drag start operation
+ * @property mouseDownTimeout
+ * @type {Number}
+ */
+ this.mouseDownTimeout = null;
+
+ this[onContextMenuWhileDragging] = this[onContextMenuWhileDragging].bind(this);
+ this[onMouseDown] = this[onMouseDown].bind(this);
+ this[onMouseMove] = this[onMouseMove].bind(this);
+ this[onMouseUp] = this[onMouseUp].bind(this);
+ this[startDrag] = this[startDrag].bind(this);
+ this[onDistanceChange] = this[onDistanceChange].bind(this);
+ }
+
+ /**
+ * Attaches sensors event listeners to the DOM
+ */
+ attach() {
+ document.addEventListener('mousedown', this[onMouseDown], true);
+ }
+
+ /**
+ * Detaches sensors event listeners to the DOM
+ */
+ detach() {
+ document.removeEventListener('mousedown', this[onMouseDown], true);
+ }
+
+ /**
+ * Mouse down handler
+ * @private
+ * @param {Event} event - Mouse down event
+ */
+ [onMouseDown](event) {
+ if (event.button !== 0 || event.ctrlKey || event.metaKey) {
+ return;
+ }
+ const container = (0, _utils.closest)(event.target, this.containers);
+
+ if (!container) {
+ return;
+ }
+
+ const { delay = 0 } = this.options;
+ const { pageX, pageY } = event;
+
+ Object.assign(this, { pageX, pageY });
+ this.onMouseDownAt = Date.now();
+ this.startEvent = event;
+
+ this.currentContainer = container;
+ document.addEventListener('mouseup', this[onMouseUp]);
+ document.addEventListener('dragstart', preventNativeDragStart);
+ document.addEventListener('mousemove', this[onDistanceChange]);
+
+ this.mouseDownTimeout = window.setTimeout(() => {
+ this[onDistanceChange]({ pageX: this.pageX, pageY: this.pageY });
+ }, delay);
+ }
+
+ /**
+ * Start the drag
+ * @private
+ */
+ [startDrag]() {
+ const startEvent = this.startEvent;
+ const container = this.currentContainer;
+
+ const dragStartEvent = new _SensorEvent.DragStartSensorEvent({
+ clientX: startEvent.clientX,
+ clientY: startEvent.clientY,
+ target: startEvent.target,
+ container,
+ originalEvent: startEvent
+ });
+
+ this.trigger(this.currentContainer, dragStartEvent);
+
+ this.dragging = !dragStartEvent.canceled();
+
+ if (this.dragging) {
+ document.addEventListener('contextmenu', this[onContextMenuWhileDragging], true);
+ document.addEventListener('mousemove', this[onMouseMove]);
+ }
+ }
+
+ /**
+ * Detect change in distance, starting drag when both
+ * delay and distance requirements are met
+ * @private
+ * @param {Event} event - Mouse move event
+ */
+ [onDistanceChange](event) {
+ const { pageX, pageY } = event;
+ const { delay, distance } = this.options;
+ const { startEvent } = this;
+
+ Object.assign(this, { pageX, pageY });
+
+ if (!this.currentContainer) {
+ return;
+ }
+
+ const timeElapsed = Date.now() - this.onMouseDownAt;
+ const distanceTravelled = (0, _utils.distance)(startEvent.pageX, startEvent.pageY, pageX, pageY) || 0;
+
+ if (timeElapsed >= delay && distanceTravelled >= distance) {
+ window.clearTimeout(this.mouseDownTimeout);
+ document.removeEventListener('mousemove', this[onDistanceChange]);
+ this[startDrag]();
+ }
+ }
+
+ /**
+ * Mouse move handler
+ * @private
+ * @param {Event} event - Mouse move event
+ */
+ [onMouseMove](event) {
+ if (!this.dragging) {
+ return;
+ }
+
+ const target = document.elementFromPoint(event.clientX, event.clientY);
+
+ const dragMoveEvent = new _SensorEvent.DragMoveSensorEvent({
+ clientX: event.clientX,
+ clientY: event.clientY,
+ target,
+ container: this.currentContainer,
+ originalEvent: event
+ });
+
+ this.trigger(this.currentContainer, dragMoveEvent);
+ }
+
+ /**
+ * Mouse up handler
+ * @private
+ * @param {Event} event - Mouse up event
+ */
+ [onMouseUp](event) {
+ clearTimeout(this.mouseDownTimeout);
+
+ if (event.button !== 0) {
+ return;
+ }
+
+ document.removeEventListener('mouseup', this[onMouseUp]);
+ document.removeEventListener('dragstart', preventNativeDragStart);
+ document.removeEventListener('mousemove', this[onDistanceChange]);
+
+ if (!this.dragging) {
+ return;
+ }
+
+ const target = document.elementFromPoint(event.clientX, event.clientY);
+
+ const dragStopEvent = new _SensorEvent.DragStopSensorEvent({
+ clientX: event.clientX,
+ clientY: event.clientY,
+ target,
+ container: this.currentContainer,
+ originalEvent: event
+ });
+
+ this.trigger(this.currentContainer, dragStopEvent);
+
+ document.removeEventListener('contextmenu', this[onContextMenuWhileDragging], true);
+ document.removeEventListener('mousemove', this[onMouseMove]);
+
+ this.currentContainer = null;
+ this.dragging = false;
+ this.startEvent = null;
+ }
+
+ /**
+ * Context menu handler
+ * @private
+ * @param {Event} event - Context menu event
+ */
+ [onContextMenuWhileDragging](event) {
+ event.preventDefault();
+ }
+}
+
+exports.default = MouseSensor;
+function preventNativeDragStart(event) {
+ event.preventDefault();
+}
+
+/***/ }),
+/* 48 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _MouseSensor = __webpack_require__(47);
+
+var _MouseSensor2 = _interopRequireDefault(_MouseSensor);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _MouseSensor2.default;
+
+/***/ }),
+/* 49 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+/**
+ * Base sensor class. Extend from this class to create a new or custom sensor
+ * @class Sensor
+ * @module Sensor
+ */
+class Sensor {
+ /**
+ * Sensor constructor.
+ * @constructs Sensor
+ * @param {HTMLElement[]|NodeList|HTMLElement} containers - Containers
+ * @param {Object} options - Options
+ */
+ constructor(containers = [], options = {}) {
+ /**
+ * Current containers
+ * @property containers
+ * @type {HTMLElement[]}
+ */
+ this.containers = [...containers];
+
+ /**
+ * Current options
+ * @property options
+ * @type {Object}
+ */
+ this.options = _extends({}, options);
+
+ /**
+ * Current drag state
+ * @property dragging
+ * @type {Boolean}
+ */
+ this.dragging = false;
+
+ /**
+ * Current container
+ * @property currentContainer
+ * @type {HTMLElement}
+ */
+ this.currentContainer = null;
+
+ /**
+ * The event of the initial sensor down
+ * @property startEvent
+ * @type {Event}
+ */
+ this.startEvent = null;
+ }
+
+ /**
+ * Attaches sensors event listeners to the DOM
+ * @return {Sensor}
+ */
+ attach() {
+ return this;
+ }
+
+ /**
+ * Detaches sensors event listeners to the DOM
+ * @return {Sensor}
+ */
+ detach() {
+ return this;
+ }
+
+ /**
+ * Adds container to this sensor instance
+ * @param {...HTMLElement} containers - Containers you want to add to this sensor
+ * @example draggable.addContainer(document.body)
+ */
+ addContainer(...containers) {
+ this.containers = [...this.containers, ...containers];
+ }
+
+ /**
+ * Removes container from this sensor instance
+ * @param {...HTMLElement} containers - Containers you want to remove from this sensor
+ * @example draggable.removeContainer(document.body)
+ */
+ removeContainer(...containers) {
+ this.containers = this.containers.filter(container => !containers.includes(container));
+ }
+
+ /**
+ * Triggers event on target element
+ * @param {HTMLElement} element - Element to trigger event on
+ * @param {SensorEvent} sensorEvent - Sensor event to trigger
+ */
+ trigger(element, sensorEvent) {
+ const event = document.createEvent('Event');
+ event.detail = sensorEvent;
+ event.initEvent(sensorEvent.type, true, true);
+ element.dispatchEvent(event);
+ this.lastEvent = sensorEvent;
+
+ return sensorEvent;
+ }
+}
+exports.default = Sensor;
+
+/***/ }),
+/* 50 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = touchCoords;
+/**
+ * Returns the first touch event found in touches or changedTouches of a touch events.
+ * @param {TouchEvent} event a touch event
+ * @return {Touch} a touch object
+ */
+function touchCoords(event = {}) {
+ const { touches, changedTouches } = event;
+ return touches && touches[0] || changedTouches && changedTouches[0];
+}
+
+/***/ }),
+/* 51 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _touchCoords = __webpack_require__(50);
+
+var _touchCoords2 = _interopRequireDefault(_touchCoords);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _touchCoords2.default;
+
+/***/ }),
+/* 52 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = distance;
+/**
+ * Returns the distance between two points
+ * @param {Number} x1 The X position of the first point
+ * @param {Number} y1 The Y position of the first point
+ * @param {Number} x2 The X position of the second point
+ * @param {Number} y2 The Y position of the second point
+ * @return {Number}
+ */
+function distance(x1, y1, x2, y2) {
+ return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
+}
+
+/***/ }),
+/* 53 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _distance = __webpack_require__(52);
+
+var _distance2 = _interopRequireDefault(_distance);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _distance2.default;
+
+/***/ }),
+/* 54 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = requestNextAnimationFrame;
+function requestNextAnimationFrame(callback) {
+ return requestAnimationFrame(() => {
+ requestAnimationFrame(callback);
+ });
+}
+
+/***/ }),
+/* 55 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _requestNextAnimationFrame = __webpack_require__(54);
+
+var _requestNextAnimationFrame2 = _interopRequireDefault(_requestNextAnimationFrame);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _requestNextAnimationFrame2.default;
+
+/***/ }),
+/* 56 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = closest;
+const matchFunction = Element.prototype.matches || Element.prototype.webkitMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector;
+
+/**
+ * Get the closest parent element of a given element that matches the given
+ * selector string or matching function
+ *
+ * @param {Element} element The child element to find a parent of
+ * @param {String|Function} selector The string or function to use to match
+ * the parent element
+ * @return {Element|null}
+ */
+function closest(element, value) {
+ if (!element) {
+ return null;
+ }
+
+ const selector = value;
+ const callback = value;
+ const nodeList = value;
+ const singleElement = value;
+
+ const isSelector = Boolean(typeof value === 'string');
+ const isFunction = Boolean(typeof value === 'function');
+ const isNodeList = Boolean(value instanceof NodeList || value instanceof Array);
+ const isElement = Boolean(value instanceof HTMLElement);
+
+ function conditionFn(currentElement) {
+ if (!currentElement) {
+ return currentElement;
+ } else if (isSelector) {
+ return matchFunction.call(currentElement, selector);
+ } else if (isNodeList) {
+ return [...nodeList].includes(currentElement);
+ } else if (isElement) {
+ return singleElement === currentElement;
+ } else if (isFunction) {
+ return callback(currentElement);
+ } else {
+ return null;
+ }
+ }
+
+ let current = element;
+
+ do {
+ current = current.correspondingUseElement || current.correspondingElement || current;
+
+ if (conditionFn(current)) {
+ return current;
+ }
+
+ current = current.parentNode;
+ } while (current && current !== document.body && current !== document);
+
+ return null;
+}
+
+/***/ }),
+/* 57 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _closest = __webpack_require__(56);
+
+var _closest2 = _interopRequireDefault(_closest);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _closest2.default;
+
+/***/ }),
+/* 58 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.defaultOptions = exports.scroll = exports.onDragStop = exports.onDragMove = exports.onDragStart = undefined;
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _AbstractPlugin = __webpack_require__(0);
+
+var _AbstractPlugin2 = _interopRequireDefault(_AbstractPlugin);
+
+var _utils = __webpack_require__(2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+const onDragStart = exports.onDragStart = Symbol('onDragStart');
+const onDragMove = exports.onDragMove = Symbol('onDragMove');
+const onDragStop = exports.onDragStop = Symbol('onDragStop');
+const scroll = exports.scroll = Symbol('scroll');
+
+/**
+ * Scrollable default options
+ * @property {Object} defaultOptions
+ * @property {Number} defaultOptions.speed
+ * @property {Number} defaultOptions.sensitivity
+ * @property {HTMLElement[]} defaultOptions.scrollableElements
+ * @type {Object}
+ */
+const defaultOptions = exports.defaultOptions = {
+ speed: 6,
+ sensitivity: 50,
+ scrollableElements: []
+};
+
+/**
+ * Scrollable plugin which scrolls the closest scrollable parent
+ * @class Scrollable
+ * @module Scrollable
+ * @extends AbstractPlugin
+ */
+class Scrollable extends _AbstractPlugin2.default {
+ /**
+ * Scrollable constructor.
+ * @constructs Scrollable
+ * @param {Draggable} draggable - Draggable instance
+ */
+ constructor(draggable) {
+ super(draggable);
+
+ /**
+ * Scrollable options
+ * @property {Object} options
+ * @property {Number} options.speed
+ * @property {Number} options.sensitivity
+ * @property {HTMLElement[]} options.scrollableElements
+ * @type {Object}
+ */
+ this.options = _extends({}, defaultOptions, this.getOptions());
+
+ /**
+ * Keeps current mouse position
+ * @property {Object} currentMousePosition
+ * @property {Number} currentMousePosition.clientX
+ * @property {Number} currentMousePosition.clientY
+ * @type {Object|null}
+ */
+ this.currentMousePosition = null;
+
+ /**
+ * Scroll animation frame
+ * @property scrollAnimationFrame
+ * @type {Number|null}
+ */
+ this.scrollAnimationFrame = null;
+
+ /**
+ * Closest scrollable element
+ * @property scrollableElement
+ * @type {HTMLElement|null}
+ */
+ this.scrollableElement = null;
+
+ /**
+ * Animation frame looking for the closest scrollable element
+ * @property findScrollableElementFrame
+ * @type {Number|null}
+ */
+ this.findScrollableElementFrame = null;
+
+ this[onDragStart] = this[onDragStart].bind(this);
+ this[onDragMove] = this[onDragMove].bind(this);
+ this[onDragStop] = this[onDragStop].bind(this);
+ this[scroll] = this[scroll].bind(this);
+ }
+
+ /**
+ * Attaches plugins event listeners
+ */
+ attach() {
+ this.draggable.on('drag:start', this[onDragStart]).on('drag:move', this[onDragMove]).on('drag:stop', this[onDragStop]);
+ }
+
+ /**
+ * Detaches plugins event listeners
+ */
+ detach() {
+ this.draggable.off('drag:start', this[onDragStart]).off('drag:move', this[onDragMove]).off('drag:stop', this[onDragStop]);
+ }
+
+ /**
+ * Returns options passed through draggable
+ * @return {Object}
+ */
+ getOptions() {
+ return this.draggable.options.scrollable || {};
+ }
+
+ /**
+ * Returns closest scrollable elements by element
+ * @param {HTMLElement} target
+ * @return {HTMLElement}
+ */
+ getScrollableElement(target) {
+ if (this.hasDefinedScrollableElements()) {
+ return (0, _utils.closest)(target, this.options.scrollableElements) || document.documentElement;
+ } else {
+ return closestScrollableElement(target);
+ }
+ }
+
+ /**
+ * Returns true if at least one scrollable element have been defined via options
+ * @param {HTMLElement} target
+ * @return {Boolean}
+ */
+ hasDefinedScrollableElements() {
+ return Boolean(this.options.scrollableElements.length !== 0);
+ }
+
+ /**
+ * Drag start handler. Finds closest scrollable parent in separate frame
+ * @param {DragStartEvent} dragEvent
+ * @private
+ */
+ [onDragStart](dragEvent) {
+ this.findScrollableElementFrame = requestAnimationFrame(() => {
+ this.scrollableElement = this.getScrollableElement(dragEvent.source);
+ });
+ }
+
+ /**
+ * Drag move handler. Remembers mouse position and initiates scrolling
+ * @param {DragMoveEvent} dragEvent
+ * @private
+ */
+ [onDragMove](dragEvent) {
+ this.findScrollableElementFrame = requestAnimationFrame(() => {
+ this.scrollableElement = this.getScrollableElement(dragEvent.sensorEvent.target);
+ });
+
+ if (!this.scrollableElement) {
+ return;
+ }
+
+ const sensorEvent = dragEvent.sensorEvent;
+ const scrollOffset = { x: 0, y: 0 };
+
+ if ('ontouchstart' in window) {
+ scrollOffset.y = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
+ scrollOffset.x = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0;
+ }
+
+ this.currentMousePosition = {
+ clientX: sensorEvent.clientX - scrollOffset.x,
+ clientY: sensorEvent.clientY - scrollOffset.y
+ };
+
+ this.scrollAnimationFrame = requestAnimationFrame(this[scroll]);
+ }
+
+ /**
+ * Drag stop handler. Cancels scroll animations and resets state
+ * @private
+ */
+ [onDragStop]() {
+ cancelAnimationFrame(this.scrollAnimationFrame);
+ cancelAnimationFrame(this.findScrollableElementFrame);
+
+ this.scrollableElement = null;
+ this.scrollAnimationFrame = null;
+ this.findScrollableElementFrame = null;
+ this.currentMousePosition = null;
+ }
+
+ /**
+ * Scroll function that does the heavylifting
+ * @private
+ */
+ [scroll]() {
+ if (!this.scrollableElement || !this.currentMousePosition) {
+ return;
+ }
+
+ cancelAnimationFrame(this.scrollAnimationFrame);
+
+ const { speed, sensitivity } = this.options;
+
+ const rect = this.scrollableElement.getBoundingClientRect();
+ const bottomCutOff = rect.bottom > window.innerHeight;
+ const topCutOff = rect.top < 0;
+ const cutOff = topCutOff || bottomCutOff;
+
+ const documentScrollingElement = getDocumentScrollingElement();
+ const scrollableElement = this.scrollableElement;
+ const clientX = this.currentMousePosition.clientX;
+ const clientY = this.currentMousePosition.clientY;
+
+ if (scrollableElement !== document.body && scrollableElement !== document.documentElement && !cutOff) {
+ const { offsetHeight, offsetWidth } = scrollableElement;
+
+ if (rect.top + offsetHeight - clientY < sensitivity) {
+ scrollableElement.scrollTop += speed;
+ } else if (clientY - rect.top < sensitivity) {
+ scrollableElement.scrollTop -= speed;
+ }
+
+ if (rect.left + offsetWidth - clientX < sensitivity) {
+ scrollableElement.scrollLeft += speed;
+ } else if (clientX - rect.left < sensitivity) {
+ scrollableElement.scrollLeft -= speed;
+ }
+ } else {
+ const { innerHeight, innerWidth } = window;
+
+ if (clientY < sensitivity) {
+ documentScrollingElement.scrollTop -= speed;
+ } else if (innerHeight - clientY < sensitivity) {
+ documentScrollingElement.scrollTop += speed;
+ }
+
+ if (clientX < sensitivity) {
+ documentScrollingElement.scrollLeft -= speed;
+ } else if (innerWidth - clientX < sensitivity) {
+ documentScrollingElement.scrollLeft += speed;
+ }
+ }
+
+ this.scrollAnimationFrame = requestAnimationFrame(this[scroll]);
+ }
+}
+
+exports.default = Scrollable; /**
+ * Returns true if the passed element has overflow
+ * @param {HTMLElement} element
+ * @return {Boolean}
+ * @private
+ */
+
+function hasOverflow(element) {
+ const overflowRegex = /(auto|scroll)/;
+ const computedStyles = getComputedStyle(element, null);
+
+ const overflow = computedStyles.getPropertyValue('overflow') + computedStyles.getPropertyValue('overflow-y') + computedStyles.getPropertyValue('overflow-x');
+
+ return overflowRegex.test(overflow);
+}
+
+/**
+ * Returns true if the passed element is statically positioned
+ * @param {HTMLElement} element
+ * @return {Boolean}
+ * @private
+ */
+function isStaticallyPositioned(element) {
+ const position = getComputedStyle(element).getPropertyValue('position');
+ return position === 'static';
+}
+
+/**
+ * Finds closest scrollable element
+ * @param {HTMLElement} element
+ * @return {HTMLElement}
+ * @private
+ */
+function closestScrollableElement(element) {
+ if (!element) {
+ return getDocumentScrollingElement();
+ }
+
+ const position = getComputedStyle(element).getPropertyValue('position');
+ const excludeStaticParents = position === 'absolute';
+
+ const scrollableElement = (0, _utils.closest)(element, parent => {
+ if (excludeStaticParents && isStaticallyPositioned(parent)) {
+ return false;
+ }
+ return hasOverflow(parent);
+ });
+
+ if (position === 'fixed' || !scrollableElement) {
+ return getDocumentScrollingElement();
+ } else {
+ return scrollableElement;
+ }
+}
+
+/**
+ * Returns element that scrolls document
+ * @return {HTMLElement}
+ * @private
+ */
+function getDocumentScrollingElement() {
+ return document.scrollingElement || document.documentElement;
+}
+
+/***/ }),
+/* 59 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.defaultOptions = undefined;
+
+var _Scrollable = __webpack_require__(58);
+
+var _Scrollable2 = _interopRequireDefault(_Scrollable);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _Scrollable2.default;
+exports.defaultOptions = _Scrollable.defaultOptions;
+
+/***/ }),
+/* 60 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.MirrorDestroyEvent = exports.MirrorMoveEvent = exports.MirrorAttachedEvent = exports.MirrorCreatedEvent = exports.MirrorCreateEvent = exports.MirrorEvent = undefined;
+
+var _AbstractEvent = __webpack_require__(1);
+
+var _AbstractEvent2 = _interopRequireDefault(_AbstractEvent);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/**
+ * Base mirror event
+ * @class MirrorEvent
+ * @module MirrorEvent
+ * @extends AbstractEvent
+ */
+class MirrorEvent extends _AbstractEvent2.default {
+ /**
+ * Draggables source element
+ * @property source
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get source() {
+ return this.data.source;
+ }
+
+ /**
+ * Draggables original source element
+ * @property originalSource
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get originalSource() {
+ return this.data.originalSource;
+ }
+
+ /**
+ * Draggables source container element
+ * @property sourceContainer
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get sourceContainer() {
+ return this.data.sourceContainer;
+ }
+
+ /**
+ * Sensor event
+ * @property sensorEvent
+ * @type {SensorEvent}
+ * @readonly
+ */
+ get sensorEvent() {
+ return this.data.sensorEvent;
+ }
+
+ /**
+ * Drag event
+ * @property dragEvent
+ * @type {DragEvent}
+ * @readonly
+ */
+ get dragEvent() {
+ return this.data.dragEvent;
+ }
+
+ /**
+ * Original event that triggered sensor event
+ * @property originalEvent
+ * @type {Event}
+ * @readonly
+ */
+ get originalEvent() {
+ if (this.sensorEvent) {
+ return this.sensorEvent.originalEvent;
+ }
+
+ return null;
+ }
+}
+
+exports.MirrorEvent = MirrorEvent; /**
+ * Mirror create event
+ * @class MirrorCreateEvent
+ * @module MirrorCreateEvent
+ * @extends MirrorEvent
+ */
+
+class MirrorCreateEvent extends MirrorEvent {}
+
+exports.MirrorCreateEvent = MirrorCreateEvent; /**
+ * Mirror created event
+ * @class MirrorCreatedEvent
+ * @module MirrorCreatedEvent
+ * @extends MirrorEvent
+ */
+
+MirrorCreateEvent.type = 'mirror:create';
+class MirrorCreatedEvent extends MirrorEvent {
+
+ /**
+ * Draggables mirror element
+ * @property mirror
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get mirror() {
+ return this.data.mirror;
+ }
+}
+
+exports.MirrorCreatedEvent = MirrorCreatedEvent; /**
+ * Mirror attached event
+ * @class MirrorAttachedEvent
+ * @module MirrorAttachedEvent
+ * @extends MirrorEvent
+ */
+
+MirrorCreatedEvent.type = 'mirror:created';
+class MirrorAttachedEvent extends MirrorEvent {
+
+ /**
+ * Draggables mirror element
+ * @property mirror
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get mirror() {
+ return this.data.mirror;
+ }
+}
+
+exports.MirrorAttachedEvent = MirrorAttachedEvent; /**
+ * Mirror move event
+ * @class MirrorMoveEvent
+ * @module MirrorMoveEvent
+ * @extends MirrorEvent
+ */
+
+MirrorAttachedEvent.type = 'mirror:attached';
+class MirrorMoveEvent extends MirrorEvent {
+
+ /**
+ * Draggables mirror element
+ * @property mirror
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get mirror() {
+ return this.data.mirror;
+ }
+
+ /**
+ * Sensor has exceeded mirror's threshold on x axis
+ * @type {Boolean}
+ * @readonly
+ */
+ get passedThreshX() {
+ return this.data.passedThreshX;
+ }
+
+ /**
+ * Sensor has exceeded mirror's threshold on y axis
+ * @type {Boolean}
+ * @readonly
+ */
+ get passedThreshY() {
+ return this.data.passedThreshY;
+ }
+}
+
+exports.MirrorMoveEvent = MirrorMoveEvent; /**
+ * Mirror destroy event
+ * @class MirrorDestroyEvent
+ * @module MirrorDestroyEvent
+ * @extends MirrorEvent
+ */
+
+MirrorMoveEvent.type = 'mirror:move';
+MirrorMoveEvent.cancelable = true;
+class MirrorDestroyEvent extends MirrorEvent {
+
+ /**
+ * Draggables mirror element
+ * @property mirror
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get mirror() {
+ return this.data.mirror;
+ }
+}
+exports.MirrorDestroyEvent = MirrorDestroyEvent;
+MirrorDestroyEvent.type = 'mirror:destroy';
+MirrorDestroyEvent.cancelable = true;
+
+/***/ }),
+/* 61 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _MirrorEvent = __webpack_require__(60);
+
+Object.keys(_MirrorEvent).forEach(function (key) {
+ if (key === "default" || key === "__esModule") return;
+ Object.defineProperty(exports, key, {
+ enumerable: true,
+ get: function () {
+ return _MirrorEvent[key];
+ }
+ });
+});
+
+/***/ }),
+/* 62 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.defaultOptions = exports.getAppendableContainer = exports.onScroll = exports.onMirrorMove = exports.onMirrorCreated = exports.onDragStop = exports.onDragMove = exports.onDragStart = undefined;
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _AbstractPlugin = __webpack_require__(0);
+
+var _AbstractPlugin2 = _interopRequireDefault(_AbstractPlugin);
+
+var _MirrorEvent = __webpack_require__(61);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
+
+const onDragStart = exports.onDragStart = Symbol('onDragStart');
+const onDragMove = exports.onDragMove = Symbol('onDragMove');
+const onDragStop = exports.onDragStop = Symbol('onDragStop');
+const onMirrorCreated = exports.onMirrorCreated = Symbol('onMirrorCreated');
+const onMirrorMove = exports.onMirrorMove = Symbol('onMirrorMove');
+const onScroll = exports.onScroll = Symbol('onScroll');
+const getAppendableContainer = exports.getAppendableContainer = Symbol('getAppendableContainer');
+
+/**
+ * Mirror default options
+ * @property {Object} defaultOptions
+ * @property {Boolean} defaultOptions.constrainDimensions
+ * @property {Boolean} defaultOptions.xAxis
+ * @property {Boolean} defaultOptions.yAxis
+ * @property {null} defaultOptions.cursorOffsetX
+ * @property {null} defaultOptions.cursorOffsetY
+ * @type {Object}
+ */
+const defaultOptions = exports.defaultOptions = {
+ constrainDimensions: false,
+ xAxis: true,
+ yAxis: true,
+ cursorOffsetX: null,
+ cursorOffsetY: null,
+ thresholdX: null,
+ thresholdY: null
+};
+
+/**
+ * Mirror plugin which controls the mirror positioning while dragging
+ * @class Mirror
+ * @module Mirror
+ * @extends AbstractPlugin
+ */
+class Mirror extends _AbstractPlugin2.default {
+ /**
+ * Mirror constructor.
+ * @constructs Mirror
+ * @param {Draggable} draggable - Draggable instance
+ */
+ constructor(draggable) {
+ super(draggable);
+
+ /**
+ * Mirror options
+ * @property {Object} options
+ * @property {Boolean} options.constrainDimensions
+ * @property {Boolean} options.xAxis
+ * @property {Boolean} options.yAxis
+ * @property {Number|null} options.cursorOffsetX
+ * @property {Number|null} options.cursorOffsetY
+ * @property {String|HTMLElement|Function} options.appendTo
+ * @type {Object}
+ */
+ this.options = _extends({}, defaultOptions, this.getOptions());
+
+ /**
+ * Scroll offset for touch devices because the mirror is positioned fixed
+ * @property {Object} scrollOffset
+ * @property {Number} scrollOffset.x
+ * @property {Number} scrollOffset.y
+ */
+ this.scrollOffset = { x: 0, y: 0 };
+
+ /**
+ * Initial scroll offset for touch devices because the mirror is positioned fixed
+ * @property {Object} scrollOffset
+ * @property {Number} scrollOffset.x
+ * @property {Number} scrollOffset.y
+ */
+ this.initialScrollOffset = {
+ x: window.scrollX,
+ y: window.scrollY
+ };
+
+ this[onDragStart] = this[onDragStart].bind(this);
+ this[onDragMove] = this[onDragMove].bind(this);
+ this[onDragStop] = this[onDragStop].bind(this);
+ this[onMirrorCreated] = this[onMirrorCreated].bind(this);
+ this[onMirrorMove] = this[onMirrorMove].bind(this);
+ this[onScroll] = this[onScroll].bind(this);
+ }
+
+ /**
+ * Attaches plugins event listeners
+ */
+ attach() {
+ this.draggable.on('drag:start', this[onDragStart]).on('drag:move', this[onDragMove]).on('drag:stop', this[onDragStop]).on('mirror:created', this[onMirrorCreated]).on('mirror:move', this[onMirrorMove]);
+ }
+
+ /**
+ * Detaches plugins event listeners
+ */
+ detach() {
+ this.draggable.off('drag:start', this[onDragStart]).off('drag:move', this[onDragMove]).off('drag:stop', this[onDragStop]).off('mirror:created', this[onMirrorCreated]).off('mirror:move', this[onMirrorMove]);
+ }
+
+ /**
+ * Returns options passed through draggable
+ * @return {Object}
+ */
+ getOptions() {
+ return this.draggable.options.mirror || {};
+ }
+
+ [onDragStart](dragEvent) {
+ if (dragEvent.canceled()) {
+ return;
+ }
+
+ if ('ontouchstart' in window) {
+ document.addEventListener('scroll', this[onScroll], true);
+ }
+
+ this.initialScrollOffset = {
+ x: window.scrollX,
+ y: window.scrollY
+ };
+
+ const { source, originalSource, sourceContainer, sensorEvent } = dragEvent;
+
+ // Last sensor position of mirror move
+ this.lastMirrorMovedClient = {
+ x: sensorEvent.clientX,
+ y: sensorEvent.clientY
+ };
+
+ const mirrorCreateEvent = new _MirrorEvent.MirrorCreateEvent({
+ source,
+ originalSource,
+ sourceContainer,
+ sensorEvent,
+ dragEvent
+ });
+
+ this.draggable.trigger(mirrorCreateEvent);
+
+ if (isNativeDragEvent(sensorEvent) || mirrorCreateEvent.canceled()) {
+ return;
+ }
+
+ const appendableContainer = this[getAppendableContainer](source) || sourceContainer;
+ this.mirror = source.cloneNode(true);
+
+ const mirrorCreatedEvent = new _MirrorEvent.MirrorCreatedEvent({
+ source,
+ originalSource,
+ sourceContainer,
+ sensorEvent,
+ dragEvent,
+ mirror: this.mirror
+ });
+
+ const mirrorAttachedEvent = new _MirrorEvent.MirrorAttachedEvent({
+ source,
+ originalSource,
+ sourceContainer,
+ sensorEvent,
+ dragEvent,
+ mirror: this.mirror
+ });
+
+ this.draggable.trigger(mirrorCreatedEvent);
+ appendableContainer.appendChild(this.mirror);
+ this.draggable.trigger(mirrorAttachedEvent);
+ }
+
+ [onDragMove](dragEvent) {
+ if (!this.mirror || dragEvent.canceled()) {
+ return;
+ }
+
+ const { source, originalSource, sourceContainer, sensorEvent } = dragEvent;
+
+ let passedThreshX = true;
+ let passedThreshY = true;
+
+ if (this.options.thresholdX || this.options.thresholdY) {
+ const { x: lastX, y: lastY } = this.lastMirrorMovedClient;
+
+ if (Math.abs(lastX - sensorEvent.clientX) < this.options.thresholdX) {
+ passedThreshX = false;
+ } else {
+ this.lastMirrorMovedClient.x = sensorEvent.clientX;
+ }
+
+ if (Math.abs(lastY - sensorEvent.clientY) < this.options.thresholdY) {
+ passedThreshY = false;
+ } else {
+ this.lastMirrorMovedClient.y = sensorEvent.clientY;
+ }
+
+ if (!passedThreshX && !passedThreshY) {
+ return;
+ }
+ }
+
+ const mirrorMoveEvent = new _MirrorEvent.MirrorMoveEvent({
+ source,
+ originalSource,
+ sourceContainer,
+ sensorEvent,
+ dragEvent,
+ mirror: this.mirror,
+ passedThreshX,
+ passedThreshY
+ });
+
+ this.draggable.trigger(mirrorMoveEvent);
+ }
+
+ [onDragStop](dragEvent) {
+ if ('ontouchstart' in window) {
+ document.removeEventListener('scroll', this[onScroll], true);
+ }
+
+ this.initialScrollOffset = { x: 0, y: 0 };
+ this.scrollOffset = { x: 0, y: 0 };
+
+ if (!this.mirror) {
+ return;
+ }
+
+ const { source, sourceContainer, sensorEvent } = dragEvent;
+
+ const mirrorDestroyEvent = new _MirrorEvent.MirrorDestroyEvent({
+ source,
+ mirror: this.mirror,
+ sourceContainer,
+ sensorEvent,
+ dragEvent
+ });
+
+ this.draggable.trigger(mirrorDestroyEvent);
+
+ if (!mirrorDestroyEvent.canceled()) {
+ this.mirror.parentNode.removeChild(this.mirror);
+ }
+ }
+
+ [onScroll]() {
+ this.scrollOffset = {
+ x: window.scrollX - this.initialScrollOffset.x,
+ y: window.scrollY - this.initialScrollOffset.y
+ };
+ }
+
+ /**
+ * Mirror created handler
+ * @param {MirrorCreatedEvent} mirrorEvent
+ * @return {Promise}
+ * @private
+ */
+ [onMirrorCreated]({ mirror, source, sensorEvent }) {
+ const mirrorClass = this.draggable.getClassNameFor('mirror');
+
+ const setState = (_ref) => {
+ let { mirrorOffset, initialX, initialY } = _ref,
+ args = _objectWithoutProperties(_ref, ['mirrorOffset', 'initialX', 'initialY']);
+
+ this.mirrorOffset = mirrorOffset;
+ this.initialX = initialX;
+ this.initialY = initialY;
+ this.lastMovedX = initialX;
+ this.lastMovedY = initialY;
+ return _extends({ mirrorOffset, initialX, initialY }, args);
+ };
+
+ mirror.style.display = 'none';
+
+ const initialState = {
+ mirror,
+ source,
+ sensorEvent,
+ mirrorClass,
+ scrollOffset: this.scrollOffset,
+ options: this.options,
+ passedThreshX: true,
+ passedThreshY: true
+ };
+
+ return Promise.resolve(initialState)
+ // Fix reflow here
+ .then(computeMirrorDimensions).then(calculateMirrorOffset).then(resetMirror).then(addMirrorClasses).then(positionMirror({ initial: true })).then(removeMirrorID).then(setState);
+ }
+
+ /**
+ * Mirror move handler
+ * @param {MirrorMoveEvent} mirrorEvent
+ * @return {Promise|null}
+ * @private
+ */
+ [onMirrorMove](mirrorEvent) {
+ if (mirrorEvent.canceled()) {
+ return null;
+ }
+
+ const setState = (_ref2) => {
+ let { lastMovedX, lastMovedY } = _ref2,
+ args = _objectWithoutProperties(_ref2, ['lastMovedX', 'lastMovedY']);
+
+ this.lastMovedX = lastMovedX;
+ this.lastMovedY = lastMovedY;
+
+ return _extends({ lastMovedX, lastMovedY }, args);
+ };
+
+ const initialState = {
+ mirror: mirrorEvent.mirror,
+ sensorEvent: mirrorEvent.sensorEvent,
+ mirrorOffset: this.mirrorOffset,
+ options: this.options,
+ initialX: this.initialX,
+ initialY: this.initialY,
+ scrollOffset: this.scrollOffset,
+ passedThreshX: mirrorEvent.passedThreshX,
+ passedThreshY: mirrorEvent.passedThreshY,
+ lastMovedX: this.lastMovedX,
+ lastMovedY: this.lastMovedY
+ };
+
+ return Promise.resolve(initialState).then(positionMirror({ raf: true })).then(setState);
+ }
+
+ /**
+ * Returns appendable container for mirror based on the appendTo option
+ * @private
+ * @param {Object} options
+ * @param {HTMLElement} options.source - Current source
+ * @return {HTMLElement}
+ */
+ [getAppendableContainer](source) {
+ const appendTo = this.options.appendTo;
+
+ if (typeof appendTo === 'string') {
+ return document.querySelector(appendTo);
+ } else if (appendTo instanceof HTMLElement) {
+ return appendTo;
+ } else if (typeof appendTo === 'function') {
+ return appendTo(source);
+ } else {
+ return source.parentNode;
+ }
+ }
+}
+
+exports.default = Mirror; /**
+ * Computes mirror dimensions based on the source element
+ * Adds sourceRect to state
+ * @param {Object} state
+ * @param {HTMLElement} state.source
+ * @return {Promise}
+ * @private
+ */
+
+function computeMirrorDimensions(_ref3) {
+ let { source } = _ref3,
+ args = _objectWithoutProperties(_ref3, ['source']);
+
+ return withPromise(resolve => {
+ const sourceRect = source.getBoundingClientRect();
+ resolve(_extends({ source, sourceRect }, args));
+ });
+}
+
+/**
+ * Calculates mirror offset
+ * Adds mirrorOffset to state
+ * @param {Object} state
+ * @param {SensorEvent} state.sensorEvent
+ * @param {DOMRect} state.sourceRect
+ * @return {Promise}
+ * @private
+ */
+function calculateMirrorOffset(_ref4) {
+ let { sensorEvent, sourceRect, options } = _ref4,
+ args = _objectWithoutProperties(_ref4, ['sensorEvent', 'sourceRect', 'options']);
+
+ return withPromise(resolve => {
+ const top = options.cursorOffsetY === null ? sensorEvent.clientY - sourceRect.top : options.cursorOffsetY;
+ const left = options.cursorOffsetX === null ? sensorEvent.clientX - sourceRect.left : options.cursorOffsetX;
+
+ const mirrorOffset = { top, left };
+
+ resolve(_extends({ sensorEvent, sourceRect, mirrorOffset, options }, args));
+ });
+}
+
+/**
+ * Applys mirror styles
+ * @param {Object} state
+ * @param {HTMLElement} state.mirror
+ * @param {HTMLElement} state.source
+ * @param {Object} state.options
+ * @return {Promise}
+ * @private
+ */
+function resetMirror(_ref5) {
+ let { mirror, source, options } = _ref5,
+ args = _objectWithoutProperties(_ref5, ['mirror', 'source', 'options']);
+
+ return withPromise(resolve => {
+ let offsetHeight;
+ let offsetWidth;
+
+ if (options.constrainDimensions) {
+ const computedSourceStyles = getComputedStyle(source);
+ offsetHeight = computedSourceStyles.getPropertyValue('height');
+ offsetWidth = computedSourceStyles.getPropertyValue('width');
+ }
+
+ mirror.style.display = null;
+ mirror.style.position = 'fixed';
+ mirror.style.pointerEvents = 'none';
+ mirror.style.top = 0;
+ mirror.style.left = 0;
+ mirror.style.margin = 0;
+
+ if (options.constrainDimensions) {
+ mirror.style.height = offsetHeight;
+ mirror.style.width = offsetWidth;
+ }
+
+ resolve(_extends({ mirror, source, options }, args));
+ });
+}
+
+/**
+ * Applys mirror class on mirror element
+ * @param {Object} state
+ * @param {HTMLElement} state.mirror
+ * @param {String} state.mirrorClass
+ * @return {Promise}
+ * @private
+ */
+function addMirrorClasses(_ref6) {
+ let { mirror, mirrorClass } = _ref6,
+ args = _objectWithoutProperties(_ref6, ['mirror', 'mirrorClass']);
+
+ return withPromise(resolve => {
+ mirror.classList.add(mirrorClass);
+ resolve(_extends({ mirror, mirrorClass }, args));
+ });
+}
+
+/**
+ * Removes source ID from cloned mirror element
+ * @param {Object} state
+ * @param {HTMLElement} state.mirror
+ * @return {Promise}
+ * @private
+ */
+function removeMirrorID(_ref7) {
+ let { mirror } = _ref7,
+ args = _objectWithoutProperties(_ref7, ['mirror']);
+
+ return withPromise(resolve => {
+ mirror.removeAttribute('id');
+ delete mirror.id;
+ resolve(_extends({ mirror }, args));
+ });
+}
+
+/**
+ * Positions mirror with translate3d
+ * @param {Object} state
+ * @param {HTMLElement} state.mirror
+ * @param {SensorEvent} state.sensorEvent
+ * @param {Object} state.mirrorOffset
+ * @param {Number} state.initialY
+ * @param {Number} state.initialX
+ * @param {Object} state.options
+ * @return {Promise}
+ * @private
+ */
+function positionMirror({ withFrame = false, initial = false } = {}) {
+ return (_ref8) => {
+ let {
+ mirror,
+ sensorEvent,
+ mirrorOffset,
+ initialY,
+ initialX,
+ scrollOffset,
+ options,
+ passedThreshX,
+ passedThreshY,
+ lastMovedX,
+ lastMovedY
+ } = _ref8,
+ args = _objectWithoutProperties(_ref8, ['mirror', 'sensorEvent', 'mirrorOffset', 'initialY', 'initialX', 'scrollOffset', 'options', 'passedThreshX', 'passedThreshY', 'lastMovedX', 'lastMovedY']);
+
+ return withPromise(resolve => {
+ const result = _extends({
+ mirror,
+ sensorEvent,
+ mirrorOffset,
+ options
+ }, args);
+
+ if (mirrorOffset) {
+ const x = passedThreshX ? Math.round((sensorEvent.clientX - mirrorOffset.left - scrollOffset.x) / (options.thresholdX || 1)) * (options.thresholdX || 1) : Math.round(lastMovedX);
+ const y = passedThreshY ? Math.round((sensorEvent.clientY - mirrorOffset.top - scrollOffset.y) / (options.thresholdY || 1)) * (options.thresholdY || 1) : Math.round(lastMovedY);
+
+ if (options.xAxis && options.yAxis || initial) {
+ mirror.style.transform = `translate3d(${x}px, ${y}px, 0)`;
+ } else if (options.xAxis && !options.yAxis) {
+ mirror.style.transform = `translate3d(${x}px, ${initialY}px, 0)`;
+ } else if (options.yAxis && !options.xAxis) {
+ mirror.style.transform = `translate3d(${initialX}px, ${y}px, 0)`;
+ }
+
+ if (initial) {
+ result.initialX = x;
+ result.initialY = y;
+ }
+
+ result.lastMovedX = x;
+ result.lastMovedY = y;
+ }
+
+ resolve(result);
+ }, { frame: withFrame });
+ };
+}
+
+/**
+ * Wraps functions in promise with potential animation frame option
+ * @param {Function} callback
+ * @param {Object} options
+ * @param {Boolean} options.raf
+ * @return {Promise}
+ * @private
+ */
+function withPromise(callback, { raf = false } = {}) {
+ return new Promise((resolve, reject) => {
+ if (raf) {
+ requestAnimationFrame(() => {
+ callback(resolve, reject);
+ });
+ } else {
+ callback(resolve, reject);
+ }
+ });
+}
+
+/**
+ * Returns true if the sensor event was triggered by a native browser drag event
+ * @param {SensorEvent} sensorEvent
+ */
+function isNativeDragEvent(sensorEvent) {
+ return (/^drag/.test(sensorEvent.originalEvent.type)
+ );
+}
+
+/***/ }),
+/* 63 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.defaultOptions = undefined;
+
+var _Mirror = __webpack_require__(62);
+
+var _Mirror2 = _interopRequireDefault(_Mirror);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _Mirror2.default;
+exports.defaultOptions = _Mirror.defaultOptions;
+
+/***/ }),
+/* 64 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _AbstractPlugin = __webpack_require__(0);
+
+var _AbstractPlugin2 = _interopRequireDefault(_AbstractPlugin);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+const onInitialize = Symbol('onInitialize');
+const onDestroy = Symbol('onDestroy');
+
+/**
+ * Focusable default options
+ * @property {Object} defaultOptions
+ * @type {Object}
+ */
+const defaultOptions = {};
+
+/**
+ * Focusable plugin
+ * @class Focusable
+ * @module Focusable
+ * @extends AbstractPlugin
+ */
+class Focusable extends _AbstractPlugin2.default {
+ /**
+ * Focusable constructor.
+ * @constructs Focusable
+ * @param {Draggable} draggable - Draggable instance
+ */
+ constructor(draggable) {
+ super(draggable);
+
+ /**
+ * Focusable options
+ * @property {Object} options
+ * @type {Object}
+ */
+ this.options = _extends({}, defaultOptions, this.getOptions());
+
+ this[onInitialize] = this[onInitialize].bind(this);
+ this[onDestroy] = this[onDestroy].bind(this);
+ }
+
+ /**
+ * Attaches listeners to draggable
+ */
+ attach() {
+ this.draggable.on('draggable:initialize', this[onInitialize]).on('draggable:destroy', this[onDestroy]);
+ }
+
+ /**
+ * Detaches listeners from draggable
+ */
+ detach() {
+ this.draggable.off('draggable:initialize', this[onInitialize]).off('draggable:destroy', this[onDestroy]);
+
+ // Remove modified elements when detach
+ this[onDestroy]();
+ }
+
+ /**
+ * Returns options passed through draggable
+ * @return {Object}
+ */
+ getOptions() {
+ return this.draggable.options.focusable || {};
+ }
+
+ /**
+ * Returns draggable containers and elements
+ * @return {HTMLElement[]}
+ */
+ getElements() {
+ return [...this.draggable.containers, ...this.draggable.getDraggableElements()];
+ }
+
+ /**
+ * Intialize handler
+ * @private
+ */
+ [onInitialize]() {
+ // Can wait until the next best frame is available
+ requestAnimationFrame(() => {
+ this.getElements().forEach(element => decorateElement(element));
+ });
+ }
+
+ /**
+ * Destroy handler
+ * @private
+ */
+ [onDestroy]() {
+ // Can wait until the next best frame is available
+ requestAnimationFrame(() => {
+ this.getElements().forEach(element => stripElement(element));
+ });
+ }
+}
+
+exports.default = Focusable; /**
+ * Keeps track of all the elements that are missing tabindex attributes
+ * so they can be reset when draggable gets destroyed
+ * @const {HTMLElement[]} elementsWithMissingTabIndex
+ */
+
+const elementsWithMissingTabIndex = [];
+
+/**
+ * Decorates element with tabindex attributes
+ * @param {HTMLElement} element
+ * @return {Object}
+ * @private
+ */
+function decorateElement(element) {
+ const hasMissingTabIndex = Boolean(!element.getAttribute('tabindex') && element.tabIndex === -1);
+
+ if (hasMissingTabIndex) {
+ elementsWithMissingTabIndex.push(element);
+ element.tabIndex = 0;
+ }
+}
+
+/**
+ * Removes elements tabindex attributes
+ * @param {HTMLElement} element
+ * @private
+ */
+function stripElement(element) {
+ const tabIndexElementPosition = elementsWithMissingTabIndex.indexOf(element);
+
+ if (tabIndexElementPosition !== -1) {
+ element.tabIndex = -1;
+ elementsWithMissingTabIndex.splice(tabIndexElementPosition, 1);
+ }
+}
+
+/***/ }),
+/* 65 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _Focusable = __webpack_require__(64);
+
+var _Focusable2 = _interopRequireDefault(_Focusable);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _Focusable2.default;
+
+/***/ }),
+/* 66 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+/**
+ * All draggable plugins inherit from this class.
+ * @abstract
+ * @class AbstractPlugin
+ * @module AbstractPlugin
+ */
+class AbstractPlugin {
+ /**
+ * AbstractPlugin constructor.
+ * @constructs AbstractPlugin
+ * @param {Draggable} draggable - Draggable instance
+ */
+ constructor(draggable) {
+ /**
+ * Draggable instance
+ * @property draggable
+ * @type {Draggable}
+ */
+ this.draggable = draggable;
+ }
+
+ /**
+ * Override to add listeners
+ * @abstract
+ */
+ attach() {
+ throw new Error('Not Implemented');
+ }
+
+ /**
+ * Override to remove listeners
+ * @abstract
+ */
+ detach() {
+ throw new Error('Not Implemented');
+ }
+}
+exports.default = AbstractPlugin;
+
+/***/ }),
+/* 67 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.defaultOptions = undefined;
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _AbstractPlugin = __webpack_require__(0);
+
+var _AbstractPlugin2 = _interopRequireDefault(_AbstractPlugin);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+const onInitialize = Symbol('onInitialize');
+const onDestroy = Symbol('onDestroy');
+const announceEvent = Symbol('announceEvent');
+const announceMessage = Symbol('announceMessage');
+
+const ARIA_RELEVANT = 'aria-relevant';
+const ARIA_ATOMIC = 'aria-atomic';
+const ARIA_LIVE = 'aria-live';
+const ROLE = 'role';
+
+/**
+ * Announcement default options
+ * @property {Object} defaultOptions
+ * @property {Number} defaultOptions.expire
+ * @type {Object}
+ */
+const defaultOptions = exports.defaultOptions = {
+ expire: 7000
+};
+
+/**
+ * Announcement plugin
+ * @class Announcement
+ * @module Announcement
+ * @extends AbstractPlugin
+ */
+class Announcement extends _AbstractPlugin2.default {
+ /**
+ * Announcement constructor.
+ * @constructs Announcement
+ * @param {Draggable} draggable - Draggable instance
+ */
+ constructor(draggable) {
+ super(draggable);
+
+ /**
+ * Plugin options
+ * @property options
+ * @type {Object}
+ */
+ this.options = _extends({}, defaultOptions, this.getOptions());
+
+ /**
+ * Original draggable trigger method. Hack until we have onAll or on('all')
+ * @property originalTriggerMethod
+ * @type {Function}
+ */
+ this.originalTriggerMethod = this.draggable.trigger;
+
+ this[onInitialize] = this[onInitialize].bind(this);
+ this[onDestroy] = this[onDestroy].bind(this);
+ }
+
+ /**
+ * Attaches listeners to draggable
+ */
+ attach() {
+ this.draggable.on('draggable:initialize', this[onInitialize]);
+ }
+
+ /**
+ * Detaches listeners from draggable
+ */
+ detach() {
+ this.draggable.off('draggable:destroy', this[onDestroy]);
+ }
+
+ /**
+ * Returns passed in options
+ */
+ getOptions() {
+ return this.draggable.options.announcements || {};
+ }
+
+ /**
+ * Announces event
+ * @private
+ * @param {AbstractEvent} event
+ */
+ [announceEvent](event) {
+ const message = this.options[event.type];
+
+ if (message && typeof message === 'string') {
+ this[announceMessage](message);
+ }
+
+ if (message && typeof message === 'function') {
+ this[announceMessage](message(event));
+ }
+ }
+
+ /**
+ * Announces message to screen reader
+ * @private
+ * @param {String} message
+ */
+ [announceMessage](message) {
+ announce(message, { expire: this.options.expire });
+ }
+
+ /**
+ * Initialize hander
+ * @private
+ */
+ [onInitialize]() {
+ // Hack until there is an api for listening for all events
+ this.draggable.trigger = event => {
+ try {
+ this[announceEvent](event);
+ } finally {
+ // Ensure that original trigger is called
+ this.originalTriggerMethod.call(this.draggable, event);
+ }
+ };
+ }
+
+ /**
+ * Destroy hander
+ * @private
+ */
+ [onDestroy]() {
+ this.draggable.trigger = this.originalTriggerMethod;
+ }
+}
+
+exports.default = Announcement; /**
+ * @const {HTMLElement} liveRegion
+ */
+
+const liveRegion = createRegion();
+
+/**
+ * Announces message via live region
+ * @param {String} message
+ * @param {Object} options
+ * @param {Number} options.expire
+ */
+function announce(message, { expire }) {
+ const element = document.createElement('div');
+
+ element.textContent = message;
+ liveRegion.appendChild(element);
+
+ return setTimeout(() => {
+ liveRegion.removeChild(element);
+ }, expire);
+}
+
+/**
+ * Creates region element
+ * @return {HTMLElement}
+ */
+function createRegion() {
+ const element = document.createElement('div');
+
+ element.setAttribute('id', 'draggable-live-region');
+ element.setAttribute(ARIA_RELEVANT, 'additions');
+ element.setAttribute(ARIA_ATOMIC, 'true');
+ element.setAttribute(ARIA_LIVE, 'assertive');
+ element.setAttribute(ROLE, 'log');
+
+ element.style.position = 'fixed';
+ element.style.width = '1px';
+ element.style.height = '1px';
+ element.style.top = '-1px';
+ element.style.overflow = 'hidden';
+
+ return element;
+}
+
+// Append live region element as early as possible
+document.addEventListener('DOMContentLoaded', () => {
+ document.body.appendChild(liveRegion);
+});
+
+/***/ }),
+/* 68 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.defaultOptions = undefined;
+
+var _Announcement = __webpack_require__(67);
+
+var _Announcement2 = _interopRequireDefault(_Announcement);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = _Announcement2.default;
+exports.defaultOptions = _Announcement.defaultOptions;
+
+/***/ }),
+/* 69 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.DraggableDestroyEvent = exports.DraggableInitializedEvent = exports.DraggableEvent = undefined;
+
+var _AbstractEvent = __webpack_require__(1);
+
+var _AbstractEvent2 = _interopRequireDefault(_AbstractEvent);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/**
+ * Base draggable event
+ * @class DraggableEvent
+ * @module DraggableEvent
+ * @extends AbstractEvent
+ */
+class DraggableEvent extends _AbstractEvent2.default {
+
+ /**
+ * Draggable instance
+ * @property draggable
+ * @type {Draggable}
+ * @readonly
+ */
+ get draggable() {
+ return this.data.draggable;
+ }
+}
+
+exports.DraggableEvent = DraggableEvent; /**
+ * Draggable initialized event
+ * @class DraggableInitializedEvent
+ * @module DraggableInitializedEvent
+ * @extends DraggableEvent
+ */
+
+DraggableEvent.type = 'draggable';
+class DraggableInitializedEvent extends DraggableEvent {}
+
+exports.DraggableInitializedEvent = DraggableInitializedEvent; /**
+ * Draggable destory event
+ * @class DraggableInitializedEvent
+ * @module DraggableDestroyEvent
+ * @extends DraggableDestroyEvent
+ */
+
+DraggableInitializedEvent.type = 'draggable:initialize';
+class DraggableDestroyEvent extends DraggableEvent {}
+exports.DraggableDestroyEvent = DraggableDestroyEvent;
+DraggableDestroyEvent.type = 'draggable:destroy';
+
+/***/ }),
+/* 70 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+const canceled = Symbol('canceled');
+
+/**
+ * All events fired by draggable inherit this class. You can call `cancel()` to
+ * cancel a specific event or you can check if an event has been canceled by
+ * calling `canceled()`.
+ * @abstract
+ * @class AbstractEvent
+ * @module AbstractEvent
+ */
+class AbstractEvent {
+
+ /**
+ * AbstractEvent constructor.
+ * @constructs AbstractEvent
+ * @param {object} data - Event data
+ */
+
+ /**
+ * Event type
+ * @static
+ * @abstract
+ * @property type
+ * @type {String}
+ */
+ constructor(data) {
+ this[canceled] = false;
+ this.data = data;
+ }
+
+ /**
+ * Read-only type
+ * @abstract
+ * @return {String}
+ */
+
+
+ /**
+ * Event cancelable
+ * @static
+ * @abstract
+ * @property cancelable
+ * @type {Boolean}
+ */
+ get type() {
+ return this.constructor.type;
+ }
+
+ /**
+ * Read-only cancelable
+ * @abstract
+ * @return {Boolean}
+ */
+ get cancelable() {
+ return this.constructor.cancelable;
+ }
+
+ /**
+ * Cancels the event instance
+ * @abstract
+ */
+ cancel() {
+ this[canceled] = true;
+ }
+
+ /**
+ * Check if event has been canceled
+ * @abstract
+ * @return {Boolean}
+ */
+ canceled() {
+ return Boolean(this[canceled]);
+ }
+
+ /**
+ * Returns new event instance with existing event data.
+ * This method allows for overriding of event data.
+ * @param {Object} data
+ * @return {AbstractEvent}
+ */
+ clone(data) {
+ return new this.constructor(_extends({}, this.data, data));
+ }
+}
+exports.default = AbstractEvent;
+AbstractEvent.type = 'event';
+AbstractEvent.cancelable = false;
+
+/***/ }),
+/* 71 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.DragStopEvent = exports.DragPressureEvent = exports.DragOutContainerEvent = exports.DragOverContainerEvent = exports.DragOutEvent = exports.DragOverEvent = exports.DragMoveEvent = exports.DragStartEvent = exports.DragEvent = undefined;
+
+var _AbstractEvent = __webpack_require__(1);
+
+var _AbstractEvent2 = _interopRequireDefault(_AbstractEvent);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/**
+ * Base drag event
+ * @class DragEvent
+ * @module DragEvent
+ * @extends AbstractEvent
+ */
+class DragEvent extends _AbstractEvent2.default {
+
+ /**
+ * Draggables source element
+ * @property source
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get source() {
+ return this.data.source;
+ }
+
+ /**
+ * Draggables original source element
+ * @property originalSource
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get originalSource() {
+ return this.data.originalSource;
+ }
+
+ /**
+ * Draggables mirror element
+ * @property mirror
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get mirror() {
+ return this.data.mirror;
+ }
+
+ /**
+ * Draggables source container element
+ * @property sourceContainer
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get sourceContainer() {
+ return this.data.sourceContainer;
+ }
+
+ /**
+ * Sensor event
+ * @property sensorEvent
+ * @type {SensorEvent}
+ * @readonly
+ */
+ get sensorEvent() {
+ return this.data.sensorEvent;
+ }
+
+ /**
+ * Original event that triggered sensor event
+ * @property originalEvent
+ * @type {Event}
+ * @readonly
+ */
+ get originalEvent() {
+ if (this.sensorEvent) {
+ return this.sensorEvent.originalEvent;
+ }
+
+ return null;
+ }
+}
+
+exports.DragEvent = DragEvent; /**
+ * Drag start event
+ * @class DragStartEvent
+ * @module DragStartEvent
+ * @extends DragEvent
+ */
+
+DragEvent.type = 'drag';
+class DragStartEvent extends DragEvent {}
+
+exports.DragStartEvent = DragStartEvent; /**
+ * Drag move event
+ * @class DragMoveEvent
+ * @module DragMoveEvent
+ * @extends DragEvent
+ */
+
+DragStartEvent.type = 'drag:start';
+DragStartEvent.cancelable = true;
+class DragMoveEvent extends DragEvent {}
+
+exports.DragMoveEvent = DragMoveEvent; /**
+ * Drag over event
+ * @class DragOverEvent
+ * @module DragOverEvent
+ * @extends DragEvent
+ */
+
+DragMoveEvent.type = 'drag:move';
+class DragOverEvent extends DragEvent {
+
+ /**
+ * Draggable container you are over
+ * @property overContainer
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get overContainer() {
+ return this.data.overContainer;
+ }
+
+ /**
+ * Draggable element you are over
+ * @property over
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get over() {
+ return this.data.over;
+ }
+}
+
+exports.DragOverEvent = DragOverEvent; /**
+ * Drag out event
+ * @class DragOutEvent
+ * @module DragOutEvent
+ * @extends DragEvent
+ */
+
+DragOverEvent.type = 'drag:over';
+DragOverEvent.cancelable = true;
+class DragOutEvent extends DragEvent {
+
+ /**
+ * Draggable container you are over
+ * @property overContainer
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get overContainer() {
+ return this.data.overContainer;
+ }
+
+ /**
+ * Draggable element you left
+ * @property over
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get over() {
+ return this.data.over;
+ }
+}
+
+exports.DragOutEvent = DragOutEvent; /**
+ * Drag over container event
+ * @class DragOverContainerEvent
+ * @module DragOverContainerEvent
+ * @extends DragEvent
+ */
+
+DragOutEvent.type = 'drag:out';
+class DragOverContainerEvent extends DragEvent {
+
+ /**
+ * Draggable container you are over
+ * @property overContainer
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get overContainer() {
+ return this.data.overContainer;
+ }
+}
+
+exports.DragOverContainerEvent = DragOverContainerEvent; /**
+ * Drag out container event
+ * @class DragOutContainerEvent
+ * @module DragOutContainerEvent
+ * @extends DragEvent
+ */
+
+DragOverContainerEvent.type = 'drag:over:container';
+class DragOutContainerEvent extends DragEvent {
+
+ /**
+ * Draggable container you left
+ * @property overContainer
+ * @type {HTMLElement}
+ * @readonly
+ */
+ get overContainer() {
+ return this.data.overContainer;
+ }
+}
+
+exports.DragOutContainerEvent = DragOutContainerEvent; /**
+ * Drag pressure event
+ * @class DragPressureEvent
+ * @module DragPressureEvent
+ * @extends DragEvent
+ */
+
+DragOutContainerEvent.type = 'drag:out:container';
+class DragPressureEvent extends DragEvent {
+
+ /**
+ * Pressure applied on draggable element
+ * @property pressure
+ * @type {Number}
+ * @readonly
+ */
+ get pressure() {
+ return this.data.pressure;
+ }
+}
+
+exports.DragPressureEvent = DragPressureEvent; /**
+ * Drag stop event
+ * @class DragStopEvent
+ * @module DragStopEvent
+ * @extends DragEvent
+ */
+
+DragPressureEvent.type = 'drag:pressure';
+class DragStopEvent extends DragEvent {}
+exports.DragStopEvent = DragStopEvent;
+DragStopEvent.type = 'drag:stop';
+
+/***/ }),
+/* 72 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.Plugins = exports.Sensors = exports.Sortable = exports.Swappable = exports.Droppable = exports.Draggable = exports.BasePlugin = exports.BaseEvent = undefined;
+
+var _Draggable = __webpack_require__(5);
+
+Object.defineProperty(exports, 'Draggable', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_Draggable).default;
+ }
+});
+
+var _Droppable = __webpack_require__(36);
+
+Object.defineProperty(exports, 'Droppable', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_Droppable).default;
+ }
+});
+
+var _Swappable = __webpack_require__(33);
+
+Object.defineProperty(exports, 'Swappable', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_Swappable).default;
+ }
+});
+
+var _Sortable = __webpack_require__(30);
+
+Object.defineProperty(exports, 'Sortable', {
+ enumerable: true,
+ get: function () {
+ return _interopRequireDefault(_Sortable).default;
+ }
+});
+
+var _AbstractEvent = __webpack_require__(1);
+
+var _AbstractEvent2 = _interopRequireDefault(_AbstractEvent);
+
+var _AbstractPlugin = __webpack_require__(0);
+
+var _AbstractPlugin2 = _interopRequireDefault(_AbstractPlugin);
+
+var _Sensors = __webpack_require__(6);
+
+var Sensors = _interopRequireWildcard(_Sensors);
+
+var _Plugins = __webpack_require__(27);
+
+var Plugins = _interopRequireWildcard(_Plugins);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.BaseEvent = _AbstractEvent2.default;
+exports.BasePlugin = _AbstractPlugin2.default;
+exports.Sensors = Sensors;
+exports.Plugins = Plugins;
+
+/***/ })
+/******/ ]);
+});
\ No newline at end of file
diff --git a/Moonlight/wwwroot/assets/js/jquery.min.js b/Moonlight/wwwroot/assets/js/jquery.min.js
new file mode 100644
index 00000000..e7e29d5b
--- /dev/null
+++ b/Moonlight/wwwroot/assets/js/jquery.min.js
@@ -0,0 +1,2 @@
+/*! jQuery v3.7.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */
+!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.0",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},R=function(){V()},M=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&z(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function X(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&M(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function U(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function z(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",R),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,""],col:[2,""],tr:[2,""],td:[3,""],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Me(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return R(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return R(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 00&&s(a.width)/e.offsetWidth||1,p=e.offsetHeight>0&&s(a.height)/e.offsetHeight||1);var u=(n(e)?t(e):window).visualViewport,l=!c()&&i,d=(a.left+(l&&u?u.offsetLeft:0))/f,h=(a.top+(l&&u?u.offsetTop:0))/p,m=a.width/f,v=a.height/p;return{width:m,height:v,top:h,right:d+m,bottom:h+v,left:d,x:d,y:h}}function u(e){var n=t(e);return{scrollLeft:n.pageXOffset,scrollTop:n.pageYOffset}}function l(e){return e?(e.nodeName||"").toLowerCase():null}function d(e){return((n(e)?e.ownerDocument:e.document)||window.document).documentElement}function h(e){return p(d(e)).left+u(e).scrollLeft}function m(e){return t(e).getComputedStyle(e)}function v(e){var t=m(e),n=t.overflow,r=t.overflowX,o=t.overflowY;return/auto|scroll|overlay|hidden/.test(n+o+r)}function y(e,n,o){void 0===o&&(o=!1);var i,a,f=r(n),c=r(n)&&function(e){var t=e.getBoundingClientRect(),n=s(t.width)/e.offsetWidth||1,r=s(t.height)/e.offsetHeight||1;return 1!==n||1!==r}(n),m=d(n),y=p(e,c,o),g={scrollLeft:0,scrollTop:0},b={x:0,y:0};return(f||!f&&!o)&&(("body"!==l(n)||v(m))&&(g=(i=n)!==t(i)&&r(i)?{scrollLeft:(a=i).scrollLeft,scrollTop:a.scrollTop}:u(i)),r(n)?((b=p(n,!0)).x+=n.clientLeft,b.y+=n.clientTop):m&&(b.x=h(m))),{x:y.left+g.scrollLeft-b.x,y:y.top+g.scrollTop-b.y,width:y.width,height:y.height}}function g(e){var t=p(e),n=e.offsetWidth,r=e.offsetHeight;return Math.abs(t.width-n)<=1&&(n=t.width),Math.abs(t.height-r)<=1&&(r=t.height),{x:e.offsetLeft,y:e.offsetTop,width:n,height:r}}function b(e){return"html"===l(e)?e:e.assignedSlot||e.parentNode||(o(e)?e.host:null)||d(e)}function x(e){return["html","body","#document"].indexOf(l(e))>=0?e.ownerDocument.body:r(e)&&v(e)?e:x(b(e))}function w(e,n){var r;void 0===n&&(n=[]);var o=x(e),i=o===(null==(r=e.ownerDocument)?void 0:r.body),a=t(o),s=i?[a].concat(a.visualViewport||[],v(o)?o:[]):o,f=n.concat(s);return i?f:f.concat(w(b(s)))}function O(e){return["table","td","th"].indexOf(l(e))>=0}function j(e){return r(e)&&"fixed"!==m(e).position?e.offsetParent:null}function E(e){for(var n=t(e),i=j(e);i&&O(i)&&"static"===m(i).position;)i=j(i);return i&&("html"===l(i)||"body"===l(i)&&"static"===m(i).position)?n:i||function(e){var t=/firefox/i.test(f());if(/Trident/i.test(f())&&r(e)&&"fixed"===m(e).position)return null;var n=b(e);for(o(n)&&(n=n.host);r(n)&&["html","body"].indexOf(l(n))<0;){var i=m(n);if("none"!==i.transform||"none"!==i.perspective||"paint"===i.contain||-1!==["transform","perspective"].indexOf(i.willChange)||t&&"filter"===i.willChange||t&&i.filter&&"none"!==i.filter)return n;n=n.parentNode}return null}(e)||n}var D="top",A="bottom",L="right",P="left",M="auto",k=[D,A,L,P],W="start",B="end",H="viewport",T="popper",R=k.reduce((function(e,t){return e.concat([t+"-"+W,t+"-"+B])}),[]),S=[].concat(k,[M]).reduce((function(e,t){return e.concat([t,t+"-"+W,t+"-"+B])}),[]),V=["beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite"];function q(e){var t=new Map,n=new Set,r=[];function o(e){n.add(e.name),[].concat(e.requires||[],e.requiresIfExists||[]).forEach((function(e){if(!n.has(e)){var r=t.get(e);r&&o(r)}})),r.push(e)}return e.forEach((function(e){t.set(e.name,e)})),e.forEach((function(e){n.has(e.name)||o(e)})),r}function C(e,t){var n=t.getRootNode&&t.getRootNode();if(e.contains(t))return!0;if(n&&o(n)){var r=t;do{if(r&&e.isSameNode(r))return!0;r=r.parentNode||r.host}while(r)}return!1}function N(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}function I(e,r,o){return r===H?N(function(e,n){var r=t(e),o=d(e),i=r.visualViewport,a=o.clientWidth,s=o.clientHeight,f=0,p=0;if(i){a=i.width,s=i.height;var u=c();(u||!u&&"fixed"===n)&&(f=i.offsetLeft,p=i.offsetTop)}return{width:a,height:s,x:f+h(e),y:p}}(e,o)):n(r)?function(e,t){var n=p(e,!1,"fixed"===t);return n.top=n.top+e.clientTop,n.left=n.left+e.clientLeft,n.bottom=n.top+e.clientHeight,n.right=n.left+e.clientWidth,n.width=e.clientWidth,n.height=e.clientHeight,n.x=n.left,n.y=n.top,n}(r,o):N(function(e){var t,n=d(e),r=u(e),o=null==(t=e.ownerDocument)?void 0:t.body,a=i(n.scrollWidth,n.clientWidth,o?o.scrollWidth:0,o?o.clientWidth:0),s=i(n.scrollHeight,n.clientHeight,o?o.scrollHeight:0,o?o.clientHeight:0),f=-r.scrollLeft+h(e),c=-r.scrollTop;return"rtl"===m(o||n).direction&&(f+=i(n.clientWidth,o?o.clientWidth:0)-a),{width:a,height:s,x:f,y:c}}(d(e)))}function _(e,t,o,s){var f="clippingParents"===t?function(e){var t=w(b(e)),o=["absolute","fixed"].indexOf(m(e).position)>=0&&r(e)?E(e):e;return n(o)?t.filter((function(e){return n(e)&&C(e,o)&&"body"!==l(e)})):[]}(e):[].concat(t),c=[].concat(f,[o]),p=c[0],u=c.reduce((function(t,n){var r=I(e,n,s);return t.top=i(r.top,t.top),t.right=a(r.right,t.right),t.bottom=a(r.bottom,t.bottom),t.left=i(r.left,t.left),t}),I(e,p,s));return u.width=u.right-u.left,u.height=u.bottom-u.top,u.x=u.left,u.y=u.top,u}function F(e){return e.split("-")[0]}function U(e){return e.split("-")[1]}function z(e){return["top","bottom"].indexOf(e)>=0?"x":"y"}function X(e){var t,n=e.reference,r=e.element,o=e.placement,i=o?F(o):null,a=o?U(o):null,s=n.x+n.width/2-r.width/2,f=n.y+n.height/2-r.height/2;switch(i){case D:t={x:s,y:n.y-r.height};break;case A:t={x:s,y:n.y+n.height};break;case L:t={x:n.x+n.width,y:f};break;case P:t={x:n.x-r.width,y:f};break;default:t={x:n.x,y:n.y}}var c=i?z(i):null;if(null!=c){var p="y"===c?"height":"width";switch(a){case W:t[c]=t[c]-(n[p]/2-r[p]/2);break;case B:t[c]=t[c]+(n[p]/2-r[p]/2)}}return t}function Y(e){return Object.assign({},{top:0,right:0,bottom:0,left:0},e)}function G(e,t){return t.reduce((function(t,n){return t[n]=e,t}),{})}function J(e,t){void 0===t&&(t={});var r=t,o=r.placement,i=void 0===o?e.placement:o,a=r.strategy,s=void 0===a?e.strategy:a,f=r.boundary,c=void 0===f?"clippingParents":f,u=r.rootBoundary,l=void 0===u?H:u,h=r.elementContext,m=void 0===h?T:h,v=r.altBoundary,y=void 0!==v&&v,g=r.padding,b=void 0===g?0:g,x=Y("number"!=typeof b?b:G(b,k)),w=m===T?"reference":T,O=e.rects.popper,j=e.elements[y?w:m],E=_(n(j)?j:j.contextElement||d(e.elements.popper),c,l,s),P=p(e.elements.reference),M=X({reference:P,element:O,strategy:"absolute",placement:i}),W=N(Object.assign({},O,M)),B=m===T?W:P,R={top:E.top-B.top+x.top,bottom:B.bottom-E.bottom+x.bottom,left:E.left-B.left+x.left,right:B.right-E.right+x.right},S=e.modifiersData.offset;if(m===T&&S){var V=S[i];Object.keys(R).forEach((function(e){var t=[L,A].indexOf(e)>=0?1:-1,n=[D,A].indexOf(e)>=0?"y":"x";R[e]+=V[n]*t}))}return R}var K={placement:"bottom",modifiers:[],strategy:"absolute"};function Q(){for(var e=arguments.length,t=new Array(e),n=0;n=0?-1:1,i="function"==typeof n?n(Object.assign({},t,{placement:e})):n,a=i[0],s=i[1];return a=a||0,s=(s||0)*o,[P,L].indexOf(r)>=0?{x:s,y:a}:{x:a,y:s}}(n,t.rects,i),e}),{}),s=a[t.placement],f=s.x,c=s.y;null!=t.modifiersData.popperOffsets&&(t.modifiersData.popperOffsets.x+=f,t.modifiersData.popperOffsets.y+=c),t.modifiersData[r]=a}},se={left:"right",right:"left",bottom:"top",top:"bottom"};function fe(e){return e.replace(/left|right|bottom|top/g,(function(e){return se[e]}))}var ce={start:"end",end:"start"};function pe(e){return e.replace(/start|end/g,(function(e){return ce[e]}))}function ue(e,t){void 0===t&&(t={});var n=t,r=n.placement,o=n.boundary,i=n.rootBoundary,a=n.padding,s=n.flipVariations,f=n.allowedAutoPlacements,c=void 0===f?S:f,p=U(r),u=p?s?R:R.filter((function(e){return U(e)===p})):k,l=u.filter((function(e){return c.indexOf(e)>=0}));0===l.length&&(l=u);var d=l.reduce((function(t,n){return t[n]=J(e,{placement:n,boundary:o,rootBoundary:i,padding:a})[F(n)],t}),{});return Object.keys(d).sort((function(e,t){return d[e]-d[t]}))}var le={name:"flip",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name;if(!t.modifiersData[r]._skip){for(var o=n.mainAxis,i=void 0===o||o,a=n.altAxis,s=void 0===a||a,f=n.fallbackPlacements,c=n.padding,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.flipVariations,h=void 0===d||d,m=n.allowedAutoPlacements,v=t.options.placement,y=F(v),g=f||(y===v||!h?[fe(v)]:function(e){if(F(e)===M)return[];var t=fe(e);return[pe(e),t,pe(t)]}(v)),b=[v].concat(g).reduce((function(e,n){return e.concat(F(n)===M?ue(t,{placement:n,boundary:p,rootBoundary:u,padding:c,flipVariations:h,allowedAutoPlacements:m}):n)}),[]),x=t.rects.reference,w=t.rects.popper,O=new Map,j=!0,E=b[0],k=0;k=0,S=R?"width":"height",V=J(t,{placement:B,boundary:p,rootBoundary:u,altBoundary:l,padding:c}),q=R?T?L:P:T?A:D;x[S]>w[S]&&(q=fe(q));var C=fe(q),N=[];if(i&&N.push(V[H]<=0),s&&N.push(V[q]<=0,V[C]<=0),N.every((function(e){return e}))){E=B,j=!1;break}O.set(B,N)}if(j)for(var I=function(e){var t=b.find((function(t){var n=O.get(t);if(n)return n.slice(0,e).every((function(e){return e}))}));if(t)return E=t,"break"},_=h?3:1;_>0;_--){if("break"===I(_))break}t.placement!==E&&(t.modifiersData[r]._skip=!0,t.placement=E,t.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function de(e,t,n){return i(e,a(t,n))}var he={name:"preventOverflow",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name,o=n.mainAxis,s=void 0===o||o,f=n.altAxis,c=void 0!==f&&f,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.padding,h=n.tether,m=void 0===h||h,v=n.tetherOffset,y=void 0===v?0:v,b=J(t,{boundary:p,rootBoundary:u,padding:d,altBoundary:l}),x=F(t.placement),w=U(t.placement),O=!w,j=z(x),M="x"===j?"y":"x",k=t.modifiersData.popperOffsets,B=t.rects.reference,H=t.rects.popper,T="function"==typeof y?y(Object.assign({},t.rects,{placement:t.placement})):y,R="number"==typeof T?{mainAxis:T,altAxis:T}:Object.assign({mainAxis:0,altAxis:0},T),S=t.modifiersData.offset?t.modifiersData.offset[t.placement]:null,V={x:0,y:0};if(k){if(s){var q,C="y"===j?D:P,N="y"===j?A:L,I="y"===j?"height":"width",_=k[j],X=_+b[C],Y=_-b[N],G=m?-H[I]/2:0,K=w===W?B[I]:H[I],Q=w===W?-H[I]:-B[I],Z=t.elements.arrow,$=m&&Z?g(Z):{width:0,height:0},ee=t.modifiersData["arrow#persistent"]?t.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},te=ee[C],ne=ee[N],re=de(0,B[I],$[I]),oe=O?B[I]/2-G-re-te-R.mainAxis:K-re-te-R.mainAxis,ie=O?-B[I]/2+G+re+ne+R.mainAxis:Q+re+ne+R.mainAxis,ae=t.elements.arrow&&E(t.elements.arrow),se=ae?"y"===j?ae.clientTop||0:ae.clientLeft||0:0,fe=null!=(q=null==S?void 0:S[j])?q:0,ce=_+ie-fe,pe=de(m?a(X,_+oe-fe-se):X,_,m?i(Y,ce):Y);k[j]=pe,V[j]=pe-_}if(c){var ue,le="x"===j?D:P,he="x"===j?A:L,me=k[M],ve="y"===M?"height":"width",ye=me+b[le],ge=me-b[he],be=-1!==[D,P].indexOf(x),xe=null!=(ue=null==S?void 0:S[M])?ue:0,we=be?ye:me-B[ve]-H[ve]-xe+R.altAxis,Oe=be?me+B[ve]+H[ve]-xe-R.altAxis:ge,je=m&&be?function(e,t,n){var r=de(e,t,n);return r>n?n:r}(we,me,Oe):de(m?we:ye,me,m?Oe:ge);k[M]=je,V[M]=je-me}t.modifiersData[r]=V}},requiresIfExists:["offset"]};var me={name:"arrow",enabled:!0,phase:"main",fn:function(e){var t,n=e.state,r=e.name,o=e.options,i=n.elements.arrow,a=n.modifiersData.popperOffsets,s=F(n.placement),f=z(s),c=[P,L].indexOf(s)>=0?"height":"width";if(i&&a){var p=function(e,t){return Y("number"!=typeof(e="function"==typeof e?e(Object.assign({},t.rects,{placement:t.placement})):e)?e:G(e,k))}(o.padding,n),u=g(i),l="y"===f?D:P,d="y"===f?A:L,h=n.rects.reference[c]+n.rects.reference[f]-a[f]-n.rects.popper[c],m=a[f]-n.rects.reference[f],v=E(i),y=v?"y"===f?v.clientHeight||0:v.clientWidth||0:0,b=h/2-m/2,x=p[l],w=y-u[c]-p[d],O=y/2-u[c]/2+b,j=de(x,O,w),M=f;n.modifiersData[r]=((t={})[M]=j,t.centerOffset=j-O,t)}},effect:function(e){var t=e.state,n=e.options.element,r=void 0===n?"[data-popper-arrow]":n;null!=r&&("string"!=typeof r||(r=t.elements.popper.querySelector(r)))&&C(t.elements.popper,r)&&(t.elements.arrow=r)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ve(e,t,n){return void 0===n&&(n={x:0,y:0}),{top:e.top-t.height-n.y,right:e.right-t.width+n.x,bottom:e.bottom-t.height+n.y,left:e.left-t.width-n.x}}function ye(e){return[D,L,A,P].some((function(t){return e[t]>=0}))}var ge={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(e){var t=e.state,n=e.name,r=t.rects.reference,o=t.rects.popper,i=t.modifiersData.preventOverflow,a=J(t,{elementContext:"reference"}),s=J(t,{altBoundary:!0}),f=ve(a,r),c=ve(s,o,i),p=ye(f),u=ye(c);t.modifiersData[n]={referenceClippingOffsets:f,popperEscapeOffsets:c,isReferenceHidden:p,hasPopperEscaped:u},t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-reference-hidden":p,"data-popper-escaped":u})}},be=Z({defaultModifiers:[ee,te,oe,ie]}),xe=[ee,te,oe,ie,ae,le,he,me,ge],we=Z({defaultModifiers:xe});e.applyStyles=ie,e.arrow=me,e.computeStyles=oe,e.createPopper=we,e.createPopperLite=be,e.defaultModifiers=xe,e.detectOverflow=J,e.eventListeners=ee,e.flip=le,e.hide=ge,e.offset=ae,e.popperGenerator=Z,e.popperOffsets=te,e.preventOverflow=he,Object.defineProperty(e,"__esModule",{value:!0})}));
+//# sourceMappingURL=popper.min.js.map
diff --git a/Moonlight/wwwroot/assets/js/toastr.min.js b/Moonlight/wwwroot/assets/js/toastr.min.js
new file mode 100644
index 00000000..b4fb8f71
--- /dev/null
+++ b/Moonlight/wwwroot/assets/js/toastr.min.js
@@ -0,0 +1 @@
+!function(e){e(["jquery"],function(e){return function(){function t(e,t,n){return g({type:O.error,iconClass:m().iconClasses.error,message:e,optionsOverride:n,title:t})}function n(t,n){return t||(t=m()),v=e("#"+t.containerId),v.length?v:(n&&(v=d(t)),v)}function o(e,t,n){return g({type:O.info,iconClass:m().iconClasses.info,message:e,optionsOverride:n,title:t})}function s(e){C=e}function i(e,t,n){return g({type:O.success,iconClass:m().iconClasses.success,message:e,optionsOverride:n,title:t})}function a(e,t,n){return g({type:O.warning,iconClass:m().iconClasses.warning,message:e,optionsOverride:n,title:t})}function r(e,t){var o=m();v||n(o),u(e,o,t)||l(o)}function c(t){var o=m();return v||n(o),t&&0===e(":focus",t).length?void h(t):void(v.children().length&&v.remove())}function l(t){for(var n=v.children(),o=n.length-1;o>=0;o--)u(e(n[o]),t)}function u(t,n,o){var s=!(!o||!o.force)&&o.force;return!(!t||!s&&0!==e(":focus",t).length)&&(t[n.hideMethod]({duration:n.hideDuration,easing:n.hideEasing,complete:function(){h(t)}}),!0)}function d(t){return v=e("").attr("id",t.containerId).addClass(t.positionClass),v.appendTo(e(t.target)),v}function p(){return{tapToDismiss:!0,toastClass:"toastr",containerId:"toastr-container",debug:!1,showMethod:"fadeIn",showDuration:300,showEasing:"swing",onShown:void 0,hideMethod:"fadeOut",hideDuration:1e3,hideEasing:"swing",onHidden:void 0,closeMethod:!1,closeDuration:!1,closeEasing:!1,closeOnHover:!0,extendedTimeOut:1e3,iconClasses:{error:"toastr-error",info:"toastr-info",success:"toastr-success",warning:"toastr-warning"},iconClass:"toastr-info",positionClass:"toastr-top-right",timeOut:5e3,titleClass:"toastr-title",messageClass:"toastr-message",escapeHtml:!1,target:"body",closeHtml:'',closeClass:"toastr-close-button",newestOnTop:!0,preventDuplicates:!1,progressBar:!1,progressClass:"toastr-progress",rtl:!1}}function f(e){C&&C(e)}function g(t){function o(e){return null==e&&(e=""),e.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">")}function s(){c(),u(),d(),p(),g(),C(),l(),i()}function i(){var e="";switch(t.iconClass){case"toastr-success":case"toastr-info":e="polite";break;default:e="assertive"}I.attr("aria-live",e)}function a(){E.closeOnHover&&I.hover(H,D),!E.onclick&&E.tapToDismiss&&I.click(b),E.closeButton&&j&&j.click(function(e){e.stopPropagation?e.stopPropagation():void 0!==e.cancelBubble&&e.cancelBubble!==!0&&(e.cancelBubble=!0),E.onCloseClick&&E.onCloseClick(e),b(!0)}),E.onclick&&I.click(function(e){E.onclick(e),b()})}function r(){I.hide(),I[E.showMethod]({duration:E.showDuration,easing:E.showEasing,complete:E.onShown}),E.timeOut>0&&(k=setTimeout(b,E.timeOut),F.maxHideTime=parseFloat(E.timeOut),F.hideEta=(new Date).getTime()+F.maxHideTime,E.progressBar&&(F.intervalId=setInterval(x,10)))}function c(){t.iconClass&&I.addClass(E.toastClass).addClass(y)}function l(){E.newestOnTop?v.prepend(I):v.append(I)}function u(){if(t.title){var e=t.title;E.escapeHtml&&(e=o(t.title)),M.append(e).addClass(E.titleClass),I.append(M)}}function d(){if(t.message){var e=t.message;E.escapeHtml&&(e=o(t.message)),B.append(e).addClass(E.messageClass),I.append(B)}}function p(){E.closeButton&&(j.addClass(E.closeClass).attr("role","button"),I.prepend(j))}function g(){E.progressBar&&(q.addClass(E.progressClass),I.prepend(q))}function C(){E.rtl&&I.addClass("rtl")}function O(e,t){if(e.preventDuplicates){if(t.message===w)return!0;w=t.message}return!1}function b(t){var n=t&&E.closeMethod!==!1?E.closeMethod:E.hideMethod,o=t&&E.closeDuration!==!1?E.closeDuration:E.hideDuration,s=t&&E.closeEasing!==!1?E.closeEasing:E.hideEasing;if(!e(":focus",I).length||t)return clearTimeout(F.intervalId),I[n]({duration:o,easing:s,complete:function(){h(I),clearTimeout(k),E.onHidden&&"hidden"!==P.state&&E.onHidden(),P.state="hidden",P.endTime=new Date,f(P)}})}function D(){(E.timeOut>0||E.extendedTimeOut>0)&&(k=setTimeout(b,E.extendedTimeOut),F.maxHideTime=parseFloat(E.extendedTimeOut),F.hideEta=(new Date).getTime()+F.maxHideTime)}function H(){clearTimeout(k),F.hideEta=0,I.stop(!0,!0)[E.showMethod]({duration:E.showDuration,easing:E.showEasing})}function x(){var e=(F.hideEta-(new Date).getTime())/F.maxHideTime*100;q.width(e+"%")}var E=m(),y=t.iconClass||E.iconClass;if("undefined"!=typeof t.optionsOverride&&(E=e.extend(E,t.optionsOverride),y=t.optionsOverride.iconClass||y),!O(E,t)){T++,v=n(E,!0);var k=null,I=e(""),M=e(""),B=e(""),q=e(""),j=e(E.closeHtml),F={intervalId:null,hideEta:null,maxHideTime:null},P={toastId:T,state:"visible",startTime:new Date,options:E,map:t};return s(),r(),a(),f(P),E.debug&&console&&console.log(P),I}}function m(){return e.extend({},p(),b.options)}function h(e){v||(v=n()),e.is(":visible")||(e.remove(),e=null,0===v.children().length&&(v.remove(),w=void 0))}var v,C,w,T=0,O={error:"error",info:"info",success:"success",warning:"warning"},b={clear:r,remove:c,error:t,getContainer:n,info:o,options:{},subscribe:s,success:i,version:"2.1.4",warning:a};return b}()})}("function"==typeof define&&define.amd?define:function(e,t){"undefined"!=typeof module&&module.exports?module.exports=t(require("jquery")):window.toastr=t(window.jQuery)});
\ No newline at end of file
diff --git a/Moonlight/wwwroot/assets/js/xterm-addon-fit.min.js b/Moonlight/wwwroot/assets/js/xterm-addon-fit.min.js
new file mode 100644
index 00000000..b423726c
--- /dev/null
+++ b/Moonlight/wwwroot/assets/js/xterm-addon-fit.min.js
@@ -0,0 +1,8 @@
+/**
+ * Skipped minification because the original files appears to be already minified.
+ * Original file: /npm/xterm-addon-fit@0.7.0/lib/xterm-addon-fit.js
+ *
+ * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
+ */
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.FitAddon=t():e.FitAddon=t()}(self,(function(){return(()=>{"use strict";var e={};return(()=>{var t=e;Object.defineProperty(t,"__esModule",{value:!0}),t.FitAddon=void 0,t.FitAddon=class{constructor(){}activate(e){this._terminal=e}dispose(){}fit(){const e=this.proposeDimensions();if(!e||!this._terminal||isNaN(e.cols)||isNaN(e.rows))return;const t=this._terminal._core;this._terminal.rows===e.rows&&this._terminal.cols===e.cols||(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}proposeDimensions(){if(!this._terminal)return;if(!this._terminal.element||!this._terminal.element.parentElement)return;const e=this._terminal._core,t=e._renderService.dimensions;if(0===t.css.cell.width||0===t.css.cell.height)return;const r=0===this._terminal.options.scrollback?0:e.viewport.scrollBarWidth,i=window.getComputedStyle(this._terminal.element.parentElement),o=parseInt(i.getPropertyValue("height")),s=Math.max(0,parseInt(i.getPropertyValue("width"))),n=window.getComputedStyle(this._terminal.element),l=o-(parseInt(n.getPropertyValue("padding-top"))+parseInt(n.getPropertyValue("padding-bottom"))),a=s-(parseInt(n.getPropertyValue("padding-right"))+parseInt(n.getPropertyValue("padding-left")))-r;return{cols:Math.max(2,Math.floor(a/t.css.cell.width)),rows:Math.max(1,Math.floor(l/t.css.cell.height))}}}})(),e})()}));
+//# sourceMappingURL=xterm-addon-fit.js.map
\ No newline at end of file