html5sortable-rails 0.9.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }());