tb_core 1.4.1 → 1.4.2

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