html5sortable-rails 0.9.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +5 -0
  5. data/Gemfile +6 -0
  6. data/Gemfile.lock +86 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +32 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/html5sortable-rails.gemspec +27 -0
  13. data/html5sortable-test/.gitignore +30 -0
  14. data/html5sortable-test/.ruby-version +1 -0
  15. data/html5sortable-test/Gemfile +62 -0
  16. data/html5sortable-test/Gemfile.lock +218 -0
  17. data/html5sortable-test/README.md +24 -0
  18. data/html5sortable-test/Rakefile +6 -0
  19. data/html5sortable-test/app/assets/config/manifest.js +3 -0
  20. data/html5sortable-test/app/assets/images/.keep +0 -0
  21. data/html5sortable-test/app/assets/javascripts/application.js +17 -0
  22. data/html5sortable-test/app/assets/javascripts/cable.js +13 -0
  23. data/html5sortable-test/app/assets/javascripts/channels/.keep +0 -0
  24. data/html5sortable-test/app/assets/stylesheets/application.css +15 -0
  25. data/html5sortable-test/app/channels/application_cable/channel.rb +4 -0
  26. data/html5sortable-test/app/channels/application_cable/connection.rb +4 -0
  27. data/html5sortable-test/app/controllers/application_controller.rb +2 -0
  28. data/html5sortable-test/app/controllers/concerns/.keep +0 -0
  29. data/html5sortable-test/app/helpers/application_helper.rb +2 -0
  30. data/html5sortable-test/app/jobs/application_job.rb +2 -0
  31. data/html5sortable-test/app/mailers/application_mailer.rb +4 -0
  32. data/html5sortable-test/app/models/application_record.rb +3 -0
  33. data/html5sortable-test/app/models/concerns/.keep +0 -0
  34. data/html5sortable-test/app/views/layouts/application.html.erb +15 -0
  35. data/html5sortable-test/app/views/layouts/mailer.html.erb +13 -0
  36. data/html5sortable-test/app/views/layouts/mailer.text.erb +1 -0
  37. data/html5sortable-test/bin/bundle +3 -0
  38. data/html5sortable-test/bin/rails +9 -0
  39. data/html5sortable-test/bin/rake +9 -0
  40. data/html5sortable-test/bin/setup +36 -0
  41. data/html5sortable-test/bin/spring +17 -0
  42. data/html5sortable-test/bin/update +31 -0
  43. data/html5sortable-test/bin/yarn +11 -0
  44. data/html5sortable-test/config.ru +5 -0
  45. data/html5sortable-test/config/application.rb +19 -0
  46. data/html5sortable-test/config/boot.rb +4 -0
  47. data/html5sortable-test/config/cable.yml +10 -0
  48. data/html5sortable-test/config/credentials.yml.enc +1 -0
  49. data/html5sortable-test/config/database.yml +25 -0
  50. data/html5sortable-test/config/environment.rb +5 -0
  51. data/html5sortable-test/config/environments/development.rb +61 -0
  52. data/html5sortable-test/config/environments/production.rb +94 -0
  53. data/html5sortable-test/config/environments/test.rb +46 -0
  54. data/html5sortable-test/config/initializers/application_controller_renderer.rb +8 -0
  55. data/html5sortable-test/config/initializers/assets.rb +14 -0
  56. data/html5sortable-test/config/initializers/backtrace_silencers.rb +7 -0
  57. data/html5sortable-test/config/initializers/content_security_policy.rb +25 -0
  58. data/html5sortable-test/config/initializers/cookies_serializer.rb +5 -0
  59. data/html5sortable-test/config/initializers/filter_parameter_logging.rb +4 -0
  60. data/html5sortable-test/config/initializers/inflections.rb +16 -0
  61. data/html5sortable-test/config/initializers/mime_types.rb +4 -0
  62. data/html5sortable-test/config/initializers/wrap_parameters.rb +14 -0
  63. data/html5sortable-test/config/locales/en.yml +33 -0
  64. data/html5sortable-test/config/puma.rb +34 -0
  65. data/html5sortable-test/config/routes.rb +3 -0
  66. data/html5sortable-test/config/spring.rb +6 -0
  67. data/html5sortable-test/config/storage.yml +34 -0
  68. data/html5sortable-test/db/seeds.rb +7 -0
  69. data/html5sortable-test/lib/assets/.keep +0 -0
  70. data/html5sortable-test/lib/tasks/.keep +0 -0
  71. data/html5sortable-test/log/.keep +0 -0
  72. data/html5sortable-test/package.json +5 -0
  73. data/html5sortable-test/public/404.html +67 -0
  74. data/html5sortable-test/public/422.html +67 -0
  75. data/html5sortable-test/public/500.html +66 -0
  76. data/html5sortable-test/public/apple-touch-icon-precomposed.png +0 -0
  77. data/html5sortable-test/public/apple-touch-icon.png +0 -0
  78. data/html5sortable-test/public/favicon.ico +0 -0
  79. data/html5sortable-test/public/robots.txt +1 -0
  80. data/html5sortable-test/test/application_system_test_case.rb +5 -0
  81. data/html5sortable-test/test/controllers/.keep +0 -0
  82. data/html5sortable-test/test/fixtures/.keep +0 -0
  83. data/html5sortable-test/test/fixtures/files/.keep +0 -0
  84. data/html5sortable-test/test/helpers/.keep +0 -0
  85. data/html5sortable-test/test/integration/.keep +0 -0
  86. data/html5sortable-test/test/mailers/.keep +0 -0
  87. data/html5sortable-test/test/models/.keep +0 -0
  88. data/html5sortable-test/test/system/.keep +0 -0
  89. data/html5sortable-test/test/test_helper.rb +10 -0
  90. data/html5sortable-test/tmp/.keep +0 -0
  91. data/html5sortable-test/vendor/.keep +0 -0
  92. data/lib/html5sortable/rails.rb +8 -0
  93. data/lib/html5sortable/rails/version.rb +6 -0
  94. data/vendor/assets/javascripts/html5sortable.js +1094 -0
  95. metadata +194 -0
@@ -0,0 +1,67 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ .rails-default-error-page {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ .rails-default-error-page div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ .rails-default-error-page div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ .rails-default-error-page h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ .rails-default-error-page div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body class="rails-default-error-page">
58
+ <!-- This file lives in public/422.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>The change you wanted was rejected.</h1>
62
+ <p>Maybe you tried to change something you didn't have access to.</p>
63
+ </div>
64
+ <p>If you are the application owner check the logs for more information.</p>
65
+ </div>
66
+ </body>
67
+ </html>
@@ -0,0 +1,66 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ .rails-default-error-page {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ .rails-default-error-page div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ .rails-default-error-page div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ .rails-default-error-page h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ .rails-default-error-page div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body class="rails-default-error-page">
58
+ <!-- This file lives in public/500.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>We're sorry, but something went wrong.</h1>
62
+ </div>
63
+ <p>If you are the application owner check the logs for more information.</p>
64
+ </div>
65
+ </body>
66
+ </html>
File without changes
File without changes
@@ -0,0 +1 @@
1
+ # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
@@ -0,0 +1,5 @@
1
+ require "test_helper"
2
+
3
+ class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
4
+ driven_by :selenium, using: :chrome, screen_size: [1400, 1400]
5
+ end
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,10 @@
1
+ ENV['RAILS_ENV'] ||= 'test'
2
+ require_relative '../config/environment'
3
+ require 'rails/test_help'
4
+
5
+ class ActiveSupport::TestCase
6
+ # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
7
+ fixtures :all
8
+
9
+ # Add more helper methods to be used by all tests here...
10
+ end
File without changes
File without changes
@@ -0,0 +1,8 @@
1
+ require "html5sortable/rails/version"
2
+
3
+ module Html5sortable
4
+ module Rails
5
+ class Engine < ::Rails::Engine
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,6 @@
1
+ module Html5sortable
2
+ module Rails
3
+ # version of html5-sortable.gem-version if gem makes no changes to library
4
+ VERSION = "0.9.3.0"
5
+ end
6
+ end
@@ -0,0 +1,1094 @@
1
+ /*
2
+ * HTML5Sortable package
3
+ * https://github.com/lukasoppermann/html5sortable
4
+ *
5
+ * Maintained by Lukas Oppermann <lukas@vea.re>
6
+ *
7
+ * Released under the MIT license.
8
+ */
9
+ var sortable = (function () {
10
+ 'use strict';
11
+
12
+ /**
13
+ * Get or set data on element
14
+ * @param {HTMLElement} element
15
+ * @param {string} key
16
+ * @param {any} value
17
+ * @return {*}
18
+ */
19
+ function addData(element, key, value) {
20
+ if (value === undefined) {
21
+ return element && element.h5s && element.h5s.data && element.h5s.data[key];
22
+ }
23
+ else {
24
+ element.h5s = element.h5s || {};
25
+ element.h5s.data = element.h5s.data || {};
26
+ element.h5s.data[key] = value;
27
+ }
28
+ }
29
+ /**
30
+ * Remove data from element
31
+ * @param {HTMLElement} element
32
+ */
33
+ function removeData(element) {
34
+ if (element.h5s) {
35
+ delete element.h5s.data;
36
+ }
37
+ }
38
+
39
+ function _filter (nodes, selector) {
40
+ if (!(nodes instanceof NodeList || nodes instanceof HTMLCollection || nodes instanceof Array)) {
41
+ throw new Error('You must provide a nodeList/HTMLCollection/Array of elements to be filtered.');
42
+ }
43
+ if (typeof selector !== 'string') {
44
+ return Array.from(nodes);
45
+ }
46
+ return Array.from(nodes).filter(function (item) { return item.nodeType === 1 && item.matches(selector); });
47
+ }
48
+
49
+ /* eslint-env browser */
50
+ var stores = new Map();
51
+ /**
52
+ * Stores data & configurations per Sortable
53
+ * @param {Object} config
54
+ */
55
+ var Store = (function () {
56
+ function Store() {
57
+ this._config = new Map(); // eslint-disable-line no-undef
58
+ this._placeholder = undefined; // eslint-disable-line no-undef
59
+ this._data = new Map(); // eslint-disable-line no-undef
60
+ }
61
+ Object.defineProperty(Store.prototype, "config", {
62
+ /**
63
+ * get the configuration map of a class instance
64
+ * @method config
65
+ * @return {object}
66
+ */
67
+ get: function () {
68
+ // transform Map to object
69
+ var config = {};
70
+ this._config.forEach(function (value, key) {
71
+ config[key] = value;
72
+ });
73
+ // return object
74
+ return config;
75
+ },
76
+ /**
77
+ * set the configuration of a class instance
78
+ * @method config
79
+ * @param {object} config object of configurations
80
+ */
81
+ set: function (config) {
82
+ if (typeof config !== 'object') {
83
+ throw new Error('You must provide a valid configuration object to the config setter.');
84
+ }
85
+ // combine config with default
86
+ var mergedConfig = Object.assign({}, config);
87
+ // add config to map
88
+ this._config = new Map(Object.entries(mergedConfig));
89
+ },
90
+ enumerable: true,
91
+ configurable: true
92
+ });
93
+ /**
94
+ * set individual configuration of a class instance
95
+ * @method setConfig
96
+ * @param key valid configuration key
97
+ * @param value any value
98
+ * @return void
99
+ */
100
+ Store.prototype.setConfig = function (key, value) {
101
+ if (!this._config.has(key)) {
102
+ throw new Error("Trying to set invalid configuration item: " + key);
103
+ }
104
+ // set config
105
+ this._config.set(key, value);
106
+ };
107
+ /**
108
+ * get an individual configuration of a class instance
109
+ * @method getConfig
110
+ * @param key valid configuration key
111
+ * @return any configuration value
112
+ */
113
+ Store.prototype.getConfig = function (key) {
114
+ if (!this._config.has(key)) {
115
+ throw new Error("Invalid configuration item requested: " + key);
116
+ }
117
+ return this._config.get(key);
118
+ };
119
+ Object.defineProperty(Store.prototype, "placeholder", {
120
+ /**
121
+ * get the placeholder for a class instance
122
+ * @method placeholder
123
+ * @return {HTMLElement|null}
124
+ */
125
+ get: function () {
126
+ return this._placeholder;
127
+ },
128
+ /**
129
+ * set the placeholder for a class instance
130
+ * @method placeholder
131
+ * @param {HTMLElement} placeholder
132
+ * @return {void}
133
+ */
134
+ set: function (placeholder) {
135
+ if (!(placeholder instanceof HTMLElement) && placeholder !== null) {
136
+ throw new Error('A placeholder must be an html element or null.');
137
+ }
138
+ this._placeholder = placeholder;
139
+ },
140
+ enumerable: true,
141
+ configurable: true
142
+ });
143
+ /**
144
+ * set an data entry
145
+ * @method setData
146
+ * @param {string} key
147
+ * @param {any} value
148
+ * @return {void}
149
+ */
150
+ Store.prototype.setData = function (key, value) {
151
+ if (typeof key !== 'string') {
152
+ throw new Error("The key must be a string.");
153
+ }
154
+ this._data.set(key, value);
155
+ };
156
+ /**
157
+ * get an data entry
158
+ * @method getData
159
+ * @param {string} key an existing key
160
+ * @return {any}
161
+ */
162
+ Store.prototype.getData = function (key) {
163
+ if (typeof key !== 'string') {
164
+ throw new Error("The key must be a string.");
165
+ }
166
+ return this._data.get(key);
167
+ };
168
+ /**
169
+ * delete an data entry
170
+ * @method deleteData
171
+ * @param {string} key an existing key
172
+ * @return {boolean}
173
+ */
174
+ Store.prototype.deleteData = function (key) {
175
+ if (typeof key !== 'string') {
176
+ throw new Error("The key must be a string.");
177
+ }
178
+ return this._data.delete(key);
179
+ };
180
+ return Store;
181
+ }());
182
+ function store (sortableElement) {
183
+ // if sortableElement is wrong type
184
+ if (!(sortableElement instanceof HTMLElement)) {
185
+ throw new Error('Please provide a sortable to the store function.');
186
+ }
187
+ // create new instance if not avilable
188
+ if (!stores.has(sortableElement)) {
189
+ stores.set(sortableElement, new Store());
190
+ }
191
+ // return instance
192
+ return stores.get(sortableElement);
193
+ }
194
+
195
+ /**
196
+ * @param {Array|HTMLElement} element
197
+ * @param {Function} callback
198
+ * @param {string} event
199
+ */
200
+ function addEventListener(element, eventName, callback) {
201
+ if (element instanceof Array) {
202
+ for (var i = 0; i < element.length; ++i) {
203
+ addEventListener(element[i], eventName, callback);
204
+ }
205
+ return;
206
+ }
207
+ element.addEventListener(eventName, callback);
208
+ store(element).setData("event" + eventName, callback);
209
+ }
210
+ /**
211
+ * @param {Array<HTMLElement>|HTMLElement} element
212
+ * @param {string} eventName
213
+ */
214
+ function removeEventListener(element, eventName) {
215
+ if (element instanceof Array) {
216
+ for (var i = 0; i < element.length; ++i) {
217
+ removeEventListener(element[i], eventName);
218
+ }
219
+ return;
220
+ }
221
+ element.removeEventListener(eventName, store(element).getData("event" + eventName));
222
+ store(element).deleteData("event" + eventName);
223
+ }
224
+
225
+ /**
226
+ * @param {Array<HTMLElement>|HTMLElement} element
227
+ * @param {string} attribute
228
+ * @param {string} value
229
+ */
230
+ function addAttribute(element, attribute, value) {
231
+ if (element instanceof Array) {
232
+ for (var i = 0; i < element.length; ++i) {
233
+ addAttribute(element[i], attribute, value);
234
+ }
235
+ return;
236
+ }
237
+ element.setAttribute(attribute, value);
238
+ }
239
+ /**
240
+ * @param {Array|HTMLElement} element
241
+ * @param {string} attribute
242
+ */
243
+ function removeAttribute(element, attribute) {
244
+ if (element instanceof Array) {
245
+ for (var i = 0; i < element.length; ++i) {
246
+ removeAttribute(element[i], attribute);
247
+ }
248
+ return;
249
+ }
250
+ element.removeAttribute(attribute);
251
+ }
252
+
253
+ function offset (element) {
254
+ if (!element.parentElement || element.getClientRects().length === 0) {
255
+ throw new Error('target element must be part of the dom');
256
+ }
257
+ var rect = element.getClientRects()[0];
258
+ return {
259
+ left: rect.left + window.scrollX,
260
+ right: rect.right + window.scrollX,
261
+ top: rect.top + window.scrollY,
262
+ bottom: rect.bottom + window.scrollY
263
+ };
264
+ }
265
+
266
+ function _debounce (func, wait) {
267
+ if (wait === void 0) { wait = 0; }
268
+ var timeout;
269
+ return function () {
270
+ var args = [];
271
+ for (var _i = 0; _i < arguments.length; _i++) {
272
+ args[_i - 0] = arguments[_i];
273
+ }
274
+ clearTimeout(timeout);
275
+ timeout = setTimeout(function () {
276
+ func.apply(void 0, args);
277
+ }, wait);
278
+ };
279
+ }
280
+
281
+ function index (element, elementList) {
282
+ if (!(element instanceof HTMLElement) || !(elementList instanceof NodeList || elementList instanceof HTMLCollection || elementList instanceof Array)) {
283
+ throw new Error('You must provide an element and a list of elements.');
284
+ }
285
+ return Array.from(elementList).indexOf(element);
286
+ }
287
+
288
+ function isInDom (element) {
289
+ if (!(element instanceof HTMLElement)) {
290
+ throw new Error('Element is not a node element.');
291
+ }
292
+ return element.parentNode !== null;
293
+ }
294
+
295
+ /* eslint-env browser */
296
+ /**
297
+ * Insert node before or after target
298
+ * @param {HTMLElement} referenceNode - reference element
299
+ * @param {HTMLElement} newElement - element to be inserted
300
+ * @param {String} position - insert before or after reference element
301
+ */
302
+ var insertNode = function (referenceNode, newElement, position) {
303
+ if (!(referenceNode instanceof HTMLElement) || !(referenceNode.parentElement instanceof HTMLElement)) {
304
+ throw new Error('target and element must be a node');
305
+ }
306
+ referenceNode.parentElement.insertBefore(newElement, (position === 'before' ? referenceNode : referenceNode.nextElementSibling));
307
+ };
308
+ /**
309
+ * Insert before target
310
+ * @param {HTMLElement} target
311
+ * @param {HTMLElement} element
312
+ */
313
+ var insertBefore = function (target, element) { return insertNode(target, element, 'before'); };
314
+ /**
315
+ * Insert after target
316
+ * @param {HTMLElement} target
317
+ * @param {HTMLElement} element
318
+ */
319
+ var insertAfter = function (target, element) { return insertNode(target, element, 'after'); };
320
+
321
+ function _serialize (sortableContainer, customItemSerializer, customContainerSerializer) {
322
+ if (customItemSerializer === void 0) { customItemSerializer = function (serializedItem, sortableContainer) { return serializedItem; }; }
323
+ if (customContainerSerializer === void 0) { customContainerSerializer = function (serializedContainer) { return serializedContainer; }; }
324
+ // check for valid sortableContainer
325
+ if (!(sortableContainer instanceof HTMLElement) || !sortableContainer.isSortable === true) {
326
+ throw new Error('You need to provide a sortableContainer to be serialized.');
327
+ }
328
+ // check for valid serializers
329
+ if (typeof customItemSerializer !== 'function' || typeof customContainerSerializer !== 'function') {
330
+ throw new Error('You need to provide a valid serializer for items and the container.');
331
+ }
332
+ // get options
333
+ var options = addData(sortableContainer, 'opts');
334
+ var item = options.items;
335
+ // serialize container
336
+ var items = _filter(sortableContainer.children, item);
337
+ var serializedItems = items.map(function (item) {
338
+ return {
339
+ parent: sortableContainer,
340
+ node: item,
341
+ html: item.outerHTML,
342
+ index: index(item, items)
343
+ };
344
+ });
345
+ // serialize container
346
+ var container = {
347
+ node: sortableContainer,
348
+ itemCount: serializedItems.length
349
+ };
350
+ return {
351
+ container: customContainerSerializer(container),
352
+ items: serializedItems.map(function (item) { return customItemSerializer(item, sortableContainer); })
353
+ };
354
+ }
355
+
356
+ function _makePlaceholder (sortableElement, placeholder, placeholderClass) {
357
+ if (placeholderClass === void 0) { placeholderClass = 'sortable-placeholder'; }
358
+ if (!(sortableElement instanceof HTMLElement)) {
359
+ throw new Error('You must provide a valid element as a sortable.');
360
+ }
361
+ // if placeholder is not an element
362
+ if (!(placeholder instanceof HTMLElement) && placeholder !== undefined) {
363
+ throw new Error('You must provide a valid element as a placeholder or set ot to undefined.');
364
+ }
365
+ // if no placeholder element is given
366
+ if (placeholder === undefined) {
367
+ if (['UL', 'OL'].includes(sortableElement.tagName)) {
368
+ placeholder = document.createElement('li');
369
+ }
370
+ else if (['TABLE', 'TBODY'].includes(sortableElement.tagName)) {
371
+ placeholder = document.createElement('tr');
372
+ // set colspan to always all rows, otherwise the item can only be dropped in first column
373
+ placeholder.innerHTML = '<td colspan="100"></td>';
374
+ }
375
+ else {
376
+ placeholder = document.createElement('div');
377
+ }
378
+ }
379
+ // add classes to placeholder
380
+ if (typeof placeholderClass === 'string') {
381
+ (_a = placeholder.classList).add.apply(_a, placeholderClass.split(' '));
382
+ }
383
+ return placeholder;
384
+ var _a;
385
+ }
386
+
387
+ function _getElementHeight (element) {
388
+ if (!(element instanceof HTMLElement)) {
389
+ throw new Error('You must provide a valid dom element');
390
+ }
391
+ // get calculated style of element
392
+ var style = window.getComputedStyle(element);
393
+ // pick applicable properties, convert to int and reduce by adding
394
+ return ['height', 'padding-top', 'padding-bottom']
395
+ .map(function (key) {
396
+ var int = parseInt(style.getPropertyValue(key), 10);
397
+ return isNaN(int) ? 0 : int;
398
+ })
399
+ .reduce(function (sum, value) { return sum + value; });
400
+ }
401
+
402
+ function _getHandles (items, selector) {
403
+ if (!(items instanceof Array)) {
404
+ throw new Error('You must provide a Array of HTMLElements to be filtered.');
405
+ }
406
+ if (typeof selector !== 'string') {
407
+ return items;
408
+ }
409
+ return items
410
+ .filter(function (item) {
411
+ return item.querySelector(selector) instanceof HTMLElement;
412
+ })
413
+ .map(function (item) {
414
+ return item.querySelector(selector);
415
+ });
416
+ }
417
+
418
+ /**
419
+ * defaultDragImage returns the current item as dragged image
420
+ * @param {HTMLElement} draggedElement - the item that the user drags
421
+ * @param {object} elementOffset - an object with the offsets top, left, right & bottom
422
+ * @param {Event} event - the original drag event object
423
+ * @return {object} with element, posX and posY properties
424
+ */
425
+ var defaultDragImage = function (draggedElement, elementOffset, event) {
426
+ return {
427
+ element: draggedElement,
428
+ posX: event.pageX - elementOffset.left,
429
+ posY: event.pageY - elementOffset.top
430
+ };
431
+ };
432
+ function setDragImage (event, draggedElement, customDragImage) {
433
+ // check if event is provided
434
+ if (!(event instanceof Event)) {
435
+ throw new Error('setDragImage requires a DragEvent as the first argument.');
436
+ }
437
+ // check if draggedElement is provided
438
+ if (!(draggedElement instanceof HTMLElement)) {
439
+ throw new Error('setDragImage requires the dragged element as the second argument.');
440
+ }
441
+ // set default function of none provided
442
+ if (!customDragImage) {
443
+ customDragImage = defaultDragImage;
444
+ }
445
+ // check if setDragImage method is available
446
+ if (event.dataTransfer && event.dataTransfer.setDragImage) {
447
+ // get the elements offset
448
+ var elementOffset = offset(draggedElement);
449
+ // get the dragImage
450
+ var dragImage = customDragImage(draggedElement, elementOffset, event);
451
+ // check if custom function returns correct values
452
+ if (!(dragImage.element instanceof HTMLElement) || typeof dragImage.posX !== 'number' || typeof dragImage.posY !== 'number') {
453
+ throw new Error('The customDragImage function you provided must return and object with the properties element[string], posX[integer], posY[integer].');
454
+ }
455
+ // needs to be set for HTML5 drag & drop to work
456
+ event.dataTransfer.effectAllowed = 'copyMove';
457
+ // Firefox requires arbitrary content in setData for the drag & drop functionality to work
458
+ event.dataTransfer.setData('text/plain', 'arbitrary');
459
+ // set the drag image on the event
460
+ event.dataTransfer.setDragImage(dragImage.element, dragImage.posX, dragImage.posY);
461
+ }
462
+ }
463
+
464
+ function _listsConnected (destination, origin) {
465
+ // check if valid sortable
466
+ if (destination.isSortable === true) {
467
+ var acceptFrom = store(destination).getConfig('acceptFrom');
468
+ // check if acceptFrom is valid
469
+ if (acceptFrom !== null && acceptFrom !== false && typeof acceptFrom !== 'string') {
470
+ throw new Error('HTML5Sortable: Wrong argument, "acceptFrom" must be "null", "false", or a valid selector string.');
471
+ }
472
+ if (acceptFrom !== null) {
473
+ return acceptFrom !== false && acceptFrom.split(',').filter(function (sel) {
474
+ return sel.length > 0 && origin.matches(sel);
475
+ }).length > 0;
476
+ }
477
+ // drop in same list
478
+ if (destination === origin) {
479
+ return true;
480
+ }
481
+ // check if lists are connected with connectWith
482
+ if (store(destination).getConfig('connectWith') !== undefined && store(destination).getConfig('connectWith') !== null) {
483
+ return store(destination).getConfig('connectWith') === store(origin).getConfig('connectWith');
484
+ }
485
+ }
486
+ return false;
487
+ }
488
+
489
+ var defaultConfiguration = {
490
+ items: null,
491
+ // deprecated
492
+ connectWith: null,
493
+ // deprecated
494
+ disableIEFix: null,
495
+ acceptFrom: null,
496
+ copy: false,
497
+ placeholder: null,
498
+ placeholderClass: 'sortable-placeholder',
499
+ draggingClass: 'sortable-dragging',
500
+ hoverClass: false,
501
+ debounce: 0,
502
+ throttleTime: 100,
503
+ maxItems: 0,
504
+ itemSerializer: undefined,
505
+ containerSerializer: undefined,
506
+ customDragImage: null
507
+ };
508
+
509
+ /**
510
+ * make sure a function is only called once within the given amount of time
511
+ * @param {Function} fn the function to throttle
512
+ * @param {number} threshold time limit for throttling
513
+ */
514
+ // must use function to keep this context
515
+ function _throttle (fn, threshold) {
516
+ var _this = this;
517
+ if (threshold === void 0) { threshold = 250; }
518
+ // check function
519
+ if (typeof fn !== 'function') {
520
+ throw new Error('You must provide a function as the first argument for throttle.');
521
+ }
522
+ // check threshold
523
+ if (typeof threshold !== 'number') {
524
+ throw new Error('You must provide a number as the second argument for throttle.');
525
+ }
526
+ var lastEventTimestamp = null;
527
+ return function () {
528
+ var args = [];
529
+ for (var _i = 0; _i < arguments.length; _i++) {
530
+ args[_i - 0] = arguments[_i];
531
+ }
532
+ var now = Date.now();
533
+ if (lastEventTimestamp === null || now - lastEventTimestamp >= threshold) {
534
+ lastEventTimestamp = now;
535
+ fn.apply(_this, args);
536
+ }
537
+ };
538
+ }
539
+
540
+ function enableHoverClass (sortableContainer, enable) {
541
+ if (typeof store(sortableContainer).getConfig('hoverClass') === 'string') {
542
+ var hoverClasses_1 = store(sortableContainer).getConfig('hoverClass').split(' ');
543
+ // add class on hover
544
+ if (enable === true) {
545
+ addEventListener(sortableContainer, 'mousemove', _throttle(function (event) {
546
+ // check of no mouse button was pressed when mousemove started == no drag
547
+ if (event.buttons === 0) {
548
+ _filter(sortableContainer.children, store(sortableContainer).getConfig('items')).forEach(function (item) {
549
+ if (item !== event.target) {
550
+ (_a = item.classList).remove.apply(_a, hoverClasses_1);
551
+ }
552
+ else {
553
+ (_b = item.classList).add.apply(_b, hoverClasses_1);
554
+ }
555
+ var _a, _b;
556
+ });
557
+ }
558
+ }, store(sortableContainer).getConfig('throttleTime')));
559
+ // remove class on leave
560
+ addEventListener(sortableContainer, 'mouseleave', function () {
561
+ _filter(sortableContainer.children, store(sortableContainer).getConfig('items')).forEach(function (item) {
562
+ (_a = item.classList).remove.apply(_a, hoverClasses_1);
563
+ var _a;
564
+ });
565
+ });
566
+ }
567
+ else {
568
+ removeEventListener(sortableContainer, 'mousemove');
569
+ removeEventListener(sortableContainer, 'mouseleave');
570
+ }
571
+ }
572
+ }
573
+
574
+ /* eslint-env browser */
575
+ /*
576
+ * variables global to the plugin
577
+ */
578
+ var dragging;
579
+ var draggingHeight;
580
+ /*
581
+ * Keeps track of the initialy selected list, where 'dragstart' event was triggered
582
+ * It allows us to move the data in between individual Sortable List instances
583
+ */
584
+ // Origin List - data from before any item was changed
585
+ var originContainer;
586
+ var originIndex;
587
+ var originElementIndex;
588
+ var originItemsBeforeUpdate;
589
+ // Destination List - data from before any item was changed
590
+ var destinationItemsBeforeUpdate;
591
+ /**
592
+ * remove event handlers from items
593
+ * @param {Array|NodeList} items
594
+ */
595
+ var _removeItemEvents = function (items) {
596
+ removeEventListener(items, 'dragstart');
597
+ removeEventListener(items, 'dragend');
598
+ removeEventListener(items, 'dragover');
599
+ removeEventListener(items, 'dragenter');
600
+ removeEventListener(items, 'drop');
601
+ removeEventListener(items, 'mouseenter');
602
+ removeEventListener(items, 'mouseleave');
603
+ };
604
+ /**
605
+ * _getDragging returns the current element to drag or
606
+ * a copy of the element.
607
+ * Is Copy Active for sortable
608
+ * @param {HTMLElement} draggedItem - the item that the user drags
609
+ * @param {HTMLElement} sortable a single sortable
610
+ */
611
+ var _getDragging = function (draggedItem, sortable) {
612
+ var ditem = draggedItem;
613
+ if (store(sortable).getConfig('copy') === true) {
614
+ ditem = draggedItem.cloneNode(true);
615
+ addAttribute(ditem, 'aria-copied', 'true');
616
+ draggedItem.parentElement.appendChild(ditem);
617
+ ditem.style.display = 'none';
618
+ ditem.oldDisplay = draggedItem.style.display;
619
+ }
620
+ return ditem;
621
+ };
622
+ /**
623
+ * Remove data from sortable
624
+ * @param {HTMLElement} sortable a single sortable
625
+ */
626
+ var _removeSortableData = function (sortable) {
627
+ removeData(sortable);
628
+ removeAttribute(sortable, 'aria-dropeffect');
629
+ };
630
+ /**
631
+ * Remove data from items
632
+ * @param {Array<HTMLElement>|HTMLElement} items
633
+ */
634
+ var _removeItemData = function (items) {
635
+ removeAttribute(items, 'aria-grabbed');
636
+ removeAttribute(items, 'aria-copied');
637
+ removeAttribute(items, 'draggable');
638
+ removeAttribute(items, 'role');
639
+ };
640
+ /**
641
+ * find sortable from element. travels up parent element until found or null.
642
+ * @param {HTMLElement} element a single sortable
643
+ */
644
+ function findSortable(element) {
645
+ while (element.isSortable !== true) {
646
+ element = element.parentElement;
647
+ }
648
+ return element;
649
+ }
650
+ /**
651
+ * Dragging event is on the sortable element. finds the top child that
652
+ * contains the element.
653
+ * @param {HTMLElement} sortableElement a single sortable
654
+ * @param {HTMLElement} element is that being dragged
655
+ */
656
+ function findDragElement(sortableElement, element) {
657
+ var options = addData(sortableElement, 'opts');
658
+ var items = _filter(sortableElement.children, options.items);
659
+ var itemlist = items.filter(function (ele) {
660
+ return ele.contains(element);
661
+ });
662
+ return itemlist.length > 0 ? itemlist[0] : element;
663
+ }
664
+ /**
665
+ * Destroy the sortable
666
+ * @param {HTMLElement} sortableElement a single sortable
667
+ */
668
+ var _destroySortable = function (sortableElement) {
669
+ var opts = addData(sortableElement, 'opts') || {};
670
+ var items = _filter(sortableElement.children, opts.items);
671
+ var handles = _getHandles(items, opts.handle);
672
+ // remove event handlers & data from sortable
673
+ removeEventListener(sortableElement, 'dragover');
674
+ removeEventListener(sortableElement, 'dragenter');
675
+ removeEventListener(sortableElement, 'drop');
676
+ // remove event data from sortable
677
+ _removeSortableData(sortableElement);
678
+ // remove event handlers & data from items
679
+ removeEventListener(handles, 'mousedown');
680
+ _removeItemEvents(items);
681
+ _removeItemData(items);
682
+ };
683
+ /**
684
+ * Enable the sortable
685
+ * @param {HTMLElement} sortableElement a single sortable
686
+ */
687
+ var _enableSortable = function (sortableElement) {
688
+ var opts = addData(sortableElement, 'opts');
689
+ var items = _filter(sortableElement.children, opts.items);
690
+ var handles = _getHandles(items, opts.handle);
691
+ addAttribute(sortableElement, 'aria-dropeffect', 'move');
692
+ addData(sortableElement, '_disabled', 'false');
693
+ addAttribute(handles, 'draggable', 'true');
694
+ // @todo: remove this fix
695
+ // IE FIX for ghost
696
+ // can be disabled as it has the side effect that other events
697
+ // (e.g. click) will be ignored
698
+ if (opts.disableIEFix === false) {
699
+ var spanEl = (document || window.document).createElement('span');
700
+ if (typeof spanEl.dragDrop === 'function') {
701
+ addEventListener(handles, 'mousedown', function () {
702
+ if (items.indexOf(this) !== -1) {
703
+ this.dragDrop();
704
+ }
705
+ else {
706
+ var parent = this.parentElement;
707
+ while (items.indexOf(parent) === -1) {
708
+ parent = parent.parentElement;
709
+ }
710
+ parent.dragDrop();
711
+ }
712
+ });
713
+ }
714
+ }
715
+ };
716
+ /**
717
+ * Disable the sortable
718
+ * @param {HTMLElement} sortableElement a single sortable
719
+ */
720
+ var _disableSortable = function (sortableElement) {
721
+ var opts = addData(sortableElement, 'opts');
722
+ var items = _filter(sortableElement.children, opts.items);
723
+ var handles = _getHandles(items, opts.handle);
724
+ addAttribute(sortableElement, 'aria-dropeffect', 'none');
725
+ addData(sortableElement, '_disabled', 'true');
726
+ addAttribute(handles, 'draggable', 'false');
727
+ removeEventListener(handles, 'mousedown');
728
+ };
729
+ /**
730
+ * Reload the sortable
731
+ * @param {HTMLElement} sortableElement a single sortable
732
+ * @description events need to be removed to not be double bound
733
+ */
734
+ var _reloadSortable = function (sortableElement) {
735
+ var opts = addData(sortableElement, 'opts');
736
+ var items = _filter(sortableElement.children, opts.items);
737
+ var handles = _getHandles(items, opts.handle);
738
+ addData(sortableElement, '_disabled', 'false');
739
+ // remove event handlers from items
740
+ _removeItemEvents(items);
741
+ removeEventListener(handles, 'mousedown');
742
+ // remove event handlers from sortable
743
+ removeEventListener(sortableElement, 'dragover');
744
+ removeEventListener(sortableElement, 'dragenter');
745
+ removeEventListener(sortableElement, 'drop');
746
+ };
747
+ /**
748
+ * Public sortable object
749
+ * @param {Array|NodeList} sortableElements
750
+ * @param {object|string} options|method
751
+ */
752
+ function sortable(sortableElements, options) {
753
+ // get method string to see if a method is called
754
+ var method = String(options);
755
+ // merge user options with defaultss
756
+ options = Object.assign({
757
+ connectWith: null,
758
+ acceptFrom: null,
759
+ copy: false,
760
+ placeholder: null,
761
+ disableIEFix: null,
762
+ placeholderClass: 'sortable-placeholder',
763
+ draggingClass: 'sortable-dragging',
764
+ hoverClass: false,
765
+ debounce: 0,
766
+ maxItems: 0,
767
+ itemSerializer: undefined,
768
+ containerSerializer: undefined,
769
+ customDragImage: null,
770
+ items: null
771
+ }, (typeof options === 'object') ? options : {});
772
+ // check if the user provided a selector instead of an element
773
+ if (typeof sortableElements === 'string') {
774
+ sortableElements = document.querySelectorAll(sortableElements);
775
+ }
776
+ // if the user provided an element, return it in an array to keep the return value consistant
777
+ if (sortableElements instanceof HTMLElement) {
778
+ sortableElements = [sortableElements];
779
+ }
780
+ sortableElements = Array.prototype.slice.call(sortableElements);
781
+ if (/serialize/.test(method)) {
782
+ return sortableElements.map(function (sortableContainer) {
783
+ var opts = addData(sortableContainer, 'opts');
784
+ return _serialize(sortableContainer, opts.itemSerializer, opts.containerSerializer);
785
+ });
786
+ }
787
+ sortableElements.forEach(function (sortableElement) {
788
+ if (/enable|disable|destroy/.test(method)) {
789
+ return sortable[method](sortableElement);
790
+ }
791
+ // log deprecation
792
+ ['connectWith', 'disableIEFix'].forEach(function (configKey) {
793
+ if (options.hasOwnProperty(configKey) && options[configKey] !== null) {
794
+ console.warn("HTML5Sortable: You are using the deprecated configuration \"" + configKey + "\". This will be removed in an upcoming version, make sure to migrate to the new options when updating.");
795
+ }
796
+ });
797
+ // merge options with default options
798
+ options = Object.assign({}, defaultConfiguration, options);
799
+ // init data store for sortable
800
+ store(sortableElement).config = options;
801
+ // get options & set options on sortable
802
+ options = addData(sortableElement, 'opts') || options;
803
+ addData(sortableElement, 'opts', options);
804
+ // property to define as sortable
805
+ sortableElement.isSortable = true;
806
+ // reset sortable
807
+ _reloadSortable(sortableElement);
808
+ // initialize
809
+ var listItems = _filter(sortableElement.children, options.items);
810
+ // create element if user defined a placeholder element as a string
811
+ var customPlaceholder;
812
+ if (options.placeholder !== null && options.placeholder !== undefined) {
813
+ var tempContainer = document.createElement(sortableElement.tagName);
814
+ tempContainer.innerHTML = options.placeholder;
815
+ customPlaceholder = tempContainer.children[0];
816
+ }
817
+ // add placeholder
818
+ store(sortableElement).placeholder = _makePlaceholder(sortableElement, customPlaceholder, options.placeholderClass);
819
+ addData(sortableElement, 'items', options.items);
820
+ if (options.acceptFrom) {
821
+ addData(sortableElement, 'acceptFrom', options.acceptFrom);
822
+ }
823
+ else if (options.connectWith) {
824
+ addData(sortableElement, 'connectWith', options.connectWith);
825
+ }
826
+ _enableSortable(sortableElement);
827
+ addAttribute(listItems, 'role', 'option');
828
+ addAttribute(listItems, 'aria-grabbed', 'false');
829
+ // enable hover class
830
+ enableHoverClass(sortableElement, true);
831
+ /*
832
+ Handle drag events on draggable items
833
+ Handle is set at the sortableElement level as it will bubble up
834
+ from the item
835
+ */
836
+ addEventListener(sortableElement, 'dragstart', function (e) {
837
+ // ignore dragstart events
838
+ if (e.target.isSortable === true) {
839
+ return;
840
+ }
841
+ e.stopImmediatePropagation();
842
+ if ((options.handle && !e.target.matches(options.handle)) || e.target.getAttribute('draggable') === 'false') {
843
+ return;
844
+ }
845
+ var sortableContainer = findSortable(e.target);
846
+ var dragItem = findDragElement(sortableContainer, e.target);
847
+ // grab values
848
+ originItemsBeforeUpdate = _filter(sortableContainer.children, options.items);
849
+ originIndex = originItemsBeforeUpdate.indexOf(dragItem);
850
+ originElementIndex = index(dragItem, sortableContainer.children);
851
+ originContainer = sortableContainer;
852
+ // add transparent clone or other ghost to cursor
853
+ setDragImage(e, dragItem, options.customDragImage);
854
+ // cache selsection & add attr for dragging
855
+ draggingHeight = _getElementHeight(dragItem);
856
+ dragItem.classList.add(options.draggingClass);
857
+ dragging = _getDragging(dragItem, sortableContainer);
858
+ addAttribute(dragging, 'aria-grabbed', 'true');
859
+ // dispatch sortstart event on each element in group
860
+ sortableContainer.dispatchEvent(new CustomEvent('sortstart', {
861
+ detail: {
862
+ origin: {
863
+ elementIndex: originElementIndex,
864
+ index: originIndex,
865
+ container: originContainer
866
+ },
867
+ item: dragging
868
+ }
869
+ }));
870
+ });
871
+ /*
872
+ We are capturing targetSortable before modifications with 'dragenter' event
873
+ */
874
+ addEventListener(sortableElement, 'dragenter', function (e) {
875
+ if (e.target.isSortable === true) {
876
+ return;
877
+ }
878
+ var sortableContainer = findSortable(e.target);
879
+ destinationItemsBeforeUpdate = _filter(sortableContainer.children, addData(sortableContainer, 'items'))
880
+ .filter(function (item) { return item !== store(sortableElement).placeholder; });
881
+ });
882
+ /*
883
+ * Dragend Event - https://developer.mozilla.org/en-US/docs/Web/Events/dragend
884
+ * Fires each time dragEvent end, or ESC pressed
885
+ * We are using it to clean up any draggable elements and placeholders
886
+ */
887
+ addEventListener(sortableElement, 'dragend', function (e) {
888
+ if (!dragging) {
889
+ return;
890
+ }
891
+ dragging.classList.remove(options.draggingClass);
892
+ addAttribute(dragging, 'aria-grabbed', 'false');
893
+ if (dragging.getAttribute('aria-copied') === 'true' && addData(dragging, 'dropped') !== 'true') {
894
+ dragging.remove();
895
+ }
896
+ dragging.style.display = dragging.oldDisplay;
897
+ delete dragging.oldDisplay;
898
+ var visiblePlaceholder = Array.from(stores.values()).map(function (data) { return data.placeholder; })
899
+ .filter(function (placeholder) { return placeholder instanceof HTMLElement; })
900
+ .filter(isInDom)[0];
901
+ if (visiblePlaceholder) {
902
+ visiblePlaceholder.remove();
903
+ }
904
+ // dispatch sortstart event on each element in group
905
+ sortableElement.dispatchEvent(new CustomEvent('sortstop', {
906
+ detail: {
907
+ origin: {
908
+ elementIndex: originElementIndex,
909
+ index: originIndex,
910
+ container: originContainer
911
+ },
912
+ item: dragging
913
+ }
914
+ }));
915
+ dragging = null;
916
+ draggingHeight = null;
917
+ });
918
+ /*
919
+ * Drop Event - https://developer.mozilla.org/en-US/docs/Web/Events/drop
920
+ * Fires when valid drop target area is hit
921
+ */
922
+ addEventListener(sortableElement, 'drop', function (e) {
923
+ if (!_listsConnected(sortableElement, dragging.parentElement)) {
924
+ return;
925
+ }
926
+ e.preventDefault();
927
+ e.stopPropagation();
928
+ addData(dragging, 'dropped', 'true');
929
+ // get the one placeholder that is currently visible
930
+ var visiblePlaceholder = Array.from(stores.values()).map(function (data) {
931
+ return data.placeholder;
932
+ })
933
+ .filter(function (placeholder) { return placeholder instanceof HTMLElement; })
934
+ .filter(isInDom)[0];
935
+ // attach element after placeholder
936
+ insertAfter(visiblePlaceholder, dragging);
937
+ // remove placeholder from dom
938
+ visiblePlaceholder.remove();
939
+ /*
940
+ * Fires Custom Event - 'sortstop'
941
+ */
942
+ sortableElement.dispatchEvent(new CustomEvent('sortstop', {
943
+ detail: {
944
+ origin: {
945
+ elementIndex: originElementIndex,
946
+ index: originIndex,
947
+ container: originContainer
948
+ },
949
+ item: dragging
950
+ }
951
+ }));
952
+ var placeholder = store(sortableElement).placeholder;
953
+ var originItems = _filter(originContainer.children, options.items)
954
+ .filter(function (item) { return item !== placeholder; });
955
+ var destinationContainer = this.isSortable === true ? this : this.parentElement;
956
+ var destinationItems = _filter(destinationContainer.children, addData(destinationContainer, 'items'))
957
+ .filter(function (item) { return item !== placeholder; });
958
+ var destinationElementIndex = index(dragging, Array.from(dragging.parentElement.children)
959
+ .filter(function (item) { return item !== placeholder; }));
960
+ var destinationIndex = index(dragging, destinationItems);
961
+ /*
962
+ * When a list item changed container lists or index within a list
963
+ * Fires Custom Event - 'sortupdate'
964
+ */
965
+ if (originElementIndex !== destinationElementIndex || originContainer !== destinationContainer) {
966
+ sortableElement.dispatchEvent(new CustomEvent('sortupdate', {
967
+ detail: {
968
+ origin: {
969
+ elementIndex: originElementIndex,
970
+ index: originIndex,
971
+ container: originContainer,
972
+ itemsBeforeUpdate: originItemsBeforeUpdate,
973
+ items: originItems
974
+ },
975
+ destination: {
976
+ index: destinationIndex,
977
+ elementIndex: destinationElementIndex,
978
+ container: destinationContainer,
979
+ itemsBeforeUpdate: destinationItemsBeforeUpdate,
980
+ items: destinationItems
981
+ },
982
+ item: dragging
983
+ }
984
+ }));
985
+ }
986
+ });
987
+ var debouncedDragOverEnter = _debounce(function (sortableElement, element, pageY) {
988
+ if (!dragging) {
989
+ return;
990
+ }
991
+ // set placeholder height if forcePlaceholderSize option is set
992
+ if (options.forcePlaceholderSize) {
993
+ store(sortableElement).placeholder.style.height = draggingHeight + 'px';
994
+ }
995
+ // if element the draggedItem is dragged onto is within the array of all elements in list
996
+ // (not only items, but also disabled, etc.)
997
+ if (Array.from(sortableElement.children).indexOf(element) > -1) {
998
+ var thisHeight = _getElementHeight(element);
999
+ var placeholderIndex = index(store(sortableElement).placeholder, element.parentElement.children);
1000
+ var thisIndex = index(element, element.parentElement.children);
1001
+ // Check if `element` is bigger than the draggable. If it is, we have to define a dead zone to prevent flickering
1002
+ if (thisHeight > draggingHeight) {
1003
+ // Dead zone?
1004
+ var deadZone = thisHeight - draggingHeight;
1005
+ var offsetTop = offset(element).top;
1006
+ if (placeholderIndex < thisIndex && pageY < offsetTop) {
1007
+ return;
1008
+ }
1009
+ if (placeholderIndex > thisIndex &&
1010
+ pageY > offsetTop + thisHeight - deadZone) {
1011
+ return;
1012
+ }
1013
+ }
1014
+ if (dragging.oldDisplay === undefined) {
1015
+ dragging.oldDisplay = dragging.style.display;
1016
+ }
1017
+ if (dragging.style.display !== 'none') {
1018
+ dragging.style.display = 'none';
1019
+ }
1020
+ // To avoid flicker, determine where to position the placeholder
1021
+ // based on where the mouse pointer is relative to the elements
1022
+ // vertical center.
1023
+ var placeAfter = false;
1024
+ try {
1025
+ var elementMiddle = offset(element).top + element.offsetHeight / 2;
1026
+ placeAfter = pageY >= elementMiddle;
1027
+ }
1028
+ catch (e) {
1029
+ placeAfter = placeholderIndex < thisIndex;
1030
+ }
1031
+ if (placeAfter) {
1032
+ insertAfter(element, store(sortableElement).placeholder);
1033
+ }
1034
+ else {
1035
+ insertBefore(element, store(sortableElement).placeholder);
1036
+ }
1037
+ // get placeholders from all stores & remove all but current one
1038
+ Array.from(stores.values())
1039
+ .filter(function (data) { return data.placeholder !== undefined; })
1040
+ .forEach(function (data) {
1041
+ if (data.placeholder !== store(sortableElement).placeholder) {
1042
+ data.placeholder.remove();
1043
+ }
1044
+ });
1045
+ }
1046
+ else {
1047
+ // get all placeholders from store
1048
+ var placeholders = Array.from(stores.values())
1049
+ .filter(function (data) { return data.placeholder !== undefined; })
1050
+ .map(function (data) {
1051
+ return data.placeholder;
1052
+ });
1053
+ // check if element is not in placeholders
1054
+ if (placeholders.indexOf(element) === -1 && sortableElement === element && !_filter(element.children, options.items).length) {
1055
+ placeholders.forEach(function (element) { return element.remove(); });
1056
+ element.appendChild(store(sortableElement).placeholder);
1057
+ }
1058
+ }
1059
+ }, options.debounce);
1060
+ // Handle dragover and dragenter events on draggable items
1061
+ var onDragOverEnter = function (e) {
1062
+ var element = e.target;
1063
+ var sortableElement = element.isSortable === true ? element : findSortable(element);
1064
+ element = findDragElement(sortableElement, element);
1065
+ if (!dragging || !_listsConnected(sortableElement, dragging.parentElement) || addData(sortableElement, '_disabled') === 'true') {
1066
+ return;
1067
+ }
1068
+ var options = addData(sortableElement, 'opts');
1069
+ if (parseInt(options.maxItems) && _filter(sortableElement.children, addData(sortableElement, 'items')).length >= parseInt(options.maxItems) && dragging.parentElement !== sortableElement) {
1070
+ return;
1071
+ }
1072
+ e.preventDefault();
1073
+ e.stopPropagation();
1074
+ e.dataTransfer.dropEffect = store(sortableElement).getConfig('copy') === true ? 'copy' : 'move';
1075
+ debouncedDragOverEnter(sortableElement, element, e.pageY);
1076
+ };
1077
+ addEventListener(listItems.concat(sortableElement), 'dragover', onDragOverEnter);
1078
+ addEventListener(listItems.concat(sortableElement), 'dragenter', onDragOverEnter);
1079
+ });
1080
+ return sortableElements;
1081
+ }
1082
+ sortable.destroy = function (sortableElement) {
1083
+ _destroySortable(sortableElement);
1084
+ };
1085
+ sortable.enable = function (sortableElement) {
1086
+ _enableSortable(sortableElement);
1087
+ };
1088
+ sortable.disable = function (sortableElement) {
1089
+ _disableSortable(sortableElement);
1090
+ };
1091
+
1092
+ return sortable;
1093
+
1094
+ }());