@natachah/vanilla-frontend 0.1.14 → 0.1.16
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.
- package/docs/main.js +3 -1
- package/docs/pages/components/drawer.html +5 -1
- package/docs/pages/components/slider.html +62 -85
- package/docs/pages/javascript/sortable.html +19 -37
- package/docs/src/js/demo.js +10 -4
- package/docs/src/js/doc-layout.js +2 -2
- package/js/_drawer.js +39 -26
- package/js/_dropdown.js +8 -2
- package/js/_slider.js +122 -141
- package/js/_sortable.js +89 -44
- package/js/tests/slider.test.js +49 -96
- package/js/tests/sortable.test.js +8 -29
- package/natachah-vanilla-frontend-0.1.16.tgz +0 -0
- package/package.json +1 -1
- package/scss/components/_slider.scss +8 -7
- package/natachah-vanilla-frontend-0.1.14.tgz +0 -0
package/js/_slider.js
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* ------------------------------------------------------------------
|
|
3
3
|
* Slider
|
|
4
4
|
* ------------------------------------------------------------------
|
|
5
|
-
* This class
|
|
5
|
+
* This class enables the functionality to make an element slider
|
|
6
6
|
*
|
|
7
7
|
* @author Natacha Herth
|
|
8
8
|
* @copyright Natacha Herth, design & web development
|
|
9
9
|
*
|
|
10
|
-
*
|
|
10
|
+
* Keep check on the scrollend event: https://caniuse.com/?search=scrollend
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import BaseComponent from './utilities/_base-component'
|
|
@@ -16,34 +16,52 @@ import ErrorMessage from "./utilities/_error"
|
|
|
16
16
|
export default class Slider extends BaseComponent {
|
|
17
17
|
|
|
18
18
|
static OPTIONS = {
|
|
19
|
-
behavior: 'smooth', // Can be auto, smooth or instant
|
|
19
|
+
behavior: 'smooth', // Can be auto, smooth, or instant
|
|
20
20
|
loop: false,
|
|
21
21
|
autoplay: false
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
* Creates an instance
|
|
25
|
+
* Creates an instance of Slider.
|
|
26
26
|
*
|
|
27
27
|
* @param {HTMLElement} el - The HTML element
|
|
28
|
-
* @param {object} options -
|
|
28
|
+
* @param {object} options - Custom options
|
|
29
29
|
* @constructor
|
|
30
30
|
*/
|
|
31
31
|
constructor(el, options = {}) {
|
|
32
32
|
|
|
33
|
-
// Check for errors
|
|
34
|
-
if (options.behavior && !['auto', 'smooth', 'instant'].includes(options.behavior))
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
// Check for errors in the options
|
|
34
|
+
if (options.behavior && !['auto', 'smooth', 'instant'].includes(options.behavior)) {
|
|
35
|
+
throw new Error(ErrorMessage.enumOf('options.behavior', 'auto|smooth|instant'))
|
|
36
|
+
}
|
|
37
|
+
if (options.loop && typeof options.loop !== 'boolean') {
|
|
38
|
+
throw new Error(ErrorMessage.typeOf('options.loop', 'boolean'))
|
|
39
|
+
}
|
|
40
|
+
if (options.autoplay && (typeof options.autoplay !== 'boolean' && typeof options.autoplay !== 'number')) {
|
|
41
|
+
throw new Error(ErrorMessage.typeOf('options.autoplay', 'boolean|number'))
|
|
42
|
+
}
|
|
37
43
|
|
|
38
44
|
// Run the SUPER constructor from BaseComponent
|
|
39
45
|
super(el, options, 'slider')
|
|
40
46
|
|
|
41
|
-
//
|
|
42
|
-
const isReduced = window.matchMedia(
|
|
47
|
+
// Handle reduced motion preferences
|
|
48
|
+
const isReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
|
43
49
|
if (isReduced) this._options.behavior = 'instant'
|
|
44
50
|
|
|
45
|
-
//
|
|
46
|
-
|
|
51
|
+
// Get slides and buttons
|
|
52
|
+
this._slides = Array.from(this._element.querySelectorAll('[role=tabpanel]'))
|
|
53
|
+
|
|
54
|
+
this._buttons = {
|
|
55
|
+
prev: document.querySelector(`[aria-controls=${this._element.id}][data-slider-prev]`),
|
|
56
|
+
next: document.querySelector(`[aria-controls=${this._element.id}][data-slider-next]`),
|
|
57
|
+
tabs: document.querySelectorAll(`[aria-controls=${this._element.id}][role=tablist] [role=tab]`)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
this._current = 0
|
|
61
|
+
this._interval = null
|
|
62
|
+
|
|
63
|
+
// Clone first and last slides if loop is enabled
|
|
64
|
+
if (this._options.loop && this._options.behavior == 'smooth') {
|
|
47
65
|
|
|
48
66
|
const cloneFirst = this._element.firstElementChild.cloneNode(true)
|
|
49
67
|
const cloneLast = this._element.lastElementChild.cloneNode(true)
|
|
@@ -60,189 +78,152 @@ export default class Slider extends BaseComponent {
|
|
|
60
78
|
|
|
61
79
|
}
|
|
62
80
|
|
|
63
|
-
//
|
|
64
|
-
this._slides = this._element.querySelectorAll('[role=tabpanel]')
|
|
65
|
-
|
|
66
|
-
this._buttons = {
|
|
67
|
-
prev: document.querySelector(`[aria-controls=${this._element.id}][data-slider-prev]`),
|
|
68
|
-
next: document.querySelector(`[aria-controls=${this._element.id}][data-slider-next]`),
|
|
69
|
-
tabs: document.querySelectorAll(`[aria-controls=${this._element.id}][role=tablist] [role=tab]`)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
this._current = 0
|
|
73
|
-
|
|
74
|
-
this._interval = null
|
|
75
|
-
|
|
81
|
+
// Initialize event listeners and functionality
|
|
76
82
|
this.#init()
|
|
77
|
-
|
|
78
83
|
}
|
|
79
84
|
|
|
80
85
|
/**
|
|
81
|
-
*
|
|
86
|
+
* Initialize event listeners and autoplay functionality.
|
|
82
87
|
*
|
|
83
88
|
* @private
|
|
84
89
|
*/
|
|
85
90
|
#init() {
|
|
86
91
|
|
|
87
|
-
//
|
|
88
|
-
if (this._options.autoplay)
|
|
92
|
+
// Handle autoplay
|
|
93
|
+
if (this._options.autoplay) {
|
|
94
|
+
this._interval = setInterval(() => this.next(), this._options.autoplay)
|
|
95
|
+
}
|
|
89
96
|
|
|
90
|
-
//
|
|
97
|
+
// Add event listeners for next and prev buttons
|
|
91
98
|
if (this._buttons.next) this._buttons.next.addEventListener('click', () => this.next())
|
|
92
|
-
|
|
93
|
-
// CLICK prev
|
|
94
99
|
if (this._buttons.prev) this._buttons.prev.addEventListener('click', () => this.prev())
|
|
95
100
|
|
|
96
|
-
//
|
|
97
|
-
if (this._buttons.tabs.length)
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
this._element.addEventListener('scroll', () => {
|
|
101
|
-
|
|
102
|
-
// Clear timeout to avoid multiple request
|
|
103
|
-
clearTimeout(this._element.scrollTimeout)
|
|
104
|
-
|
|
105
|
-
// Run event before changed
|
|
106
|
-
this.emmitEvent('changing', { current: this._current })
|
|
107
|
-
|
|
108
|
-
// Set the timeout
|
|
109
|
-
this._element.scrollTimeout = setTimeout(() => {
|
|
110
|
-
|
|
111
|
-
// Check loop on scrolling
|
|
112
|
-
if (this._options.loop) this.#loop()
|
|
113
|
-
|
|
114
|
-
// Toggle the attributes
|
|
115
|
-
this.#change()
|
|
116
|
-
|
|
117
|
-
}, 150)
|
|
101
|
+
// Add event listeners for tabs
|
|
102
|
+
if (this._buttons.tabs.length) {
|
|
103
|
+
this._buttons.tabs.forEach((tab, index) => tab.addEventListener('click', () => this.goTo(index)))
|
|
104
|
+
}
|
|
118
105
|
|
|
119
|
-
|
|
120
|
-
|
|
106
|
+
// Handle autoplay reset after user interaction
|
|
107
|
+
if (this._options.autoplay) {
|
|
108
|
+
this._element.addEventListener('click', () => {
|
|
121
109
|
clearInterval(this._interval)
|
|
122
110
|
this._interval = setInterval(() => this.next(), this._options.autoplay)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Change the current slide and toggle the attributes
|
|
131
|
-
*
|
|
132
|
-
* @private
|
|
133
|
-
*/
|
|
134
|
-
#change() {
|
|
135
|
-
|
|
136
|
-
// Define the index
|
|
137
|
-
const index = this._slides.length - [...this._slides].reverse().findIndex((slide) => this._element.scrollLeft >= slide.offsetLeft) - 1
|
|
138
|
-
|
|
139
|
-
// Check if index change to avoid multiple call
|
|
140
|
-
if (index !== this._current) {
|
|
141
|
-
|
|
142
|
-
// Define the new current
|
|
143
|
-
this._current = index
|
|
144
|
-
|
|
145
|
-
// Change the [aria-selected] attribute on tabs
|
|
146
|
-
this._buttons.tabs.forEach((tab, index) => tab.setAttribute('aria-selected', index === this._current))
|
|
147
|
-
|
|
148
|
-
// Change the [aria-hidden] attribute on slide
|
|
149
|
-
this._slides.forEach((slide, index) => slide.setAttribute('aria-hidden', index !== this._current))
|
|
111
|
+
})
|
|
112
|
+
}
|
|
150
113
|
|
|
151
|
-
|
|
152
|
-
|
|
114
|
+
// Enable swipe functionality on touch devices.
|
|
115
|
+
if (!this._options.autoplay) {
|
|
116
|
+
let startX = 0
|
|
153
117
|
|
|
154
|
-
|
|
155
|
-
|
|
118
|
+
const onTouchStart = (event) => {
|
|
119
|
+
startX = event.touches[0].clientX
|
|
120
|
+
}
|
|
156
121
|
|
|
157
|
-
|
|
158
|
-
|
|
122
|
+
const onTouchEnd = (event) => {
|
|
123
|
+
const endX = event.changedTouches[0].clientX
|
|
124
|
+
if (startX > endX + 50) {
|
|
125
|
+
this.next()
|
|
126
|
+
} else if (startX < endX - 50) {
|
|
127
|
+
this.prev()
|
|
128
|
+
}
|
|
129
|
+
}
|
|
159
130
|
|
|
131
|
+
this._element.addEventListener('touchstart', onTouchStart)
|
|
132
|
+
this._element.addEventListener('touchend', onTouchEnd)
|
|
160
133
|
}
|
|
161
|
-
|
|
162
134
|
}
|
|
163
135
|
|
|
164
136
|
/**
|
|
165
|
-
*
|
|
137
|
+
* Go to a specific slide by index.
|
|
166
138
|
*
|
|
167
|
-
* @
|
|
168
|
-
* @private
|
|
139
|
+
* @param {int} index - The index of the slide
|
|
169
140
|
*/
|
|
170
|
-
|
|
141
|
+
goTo(index) {
|
|
171
142
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
this._element.scrollTo(this._slides[this._slides.length - 1].offsetLeft, 0)
|
|
175
|
-
return
|
|
143
|
+
if (typeof index !== 'number') {
|
|
144
|
+
throw new Error(ErrorMessage.typeOf('index', 'number'))
|
|
176
145
|
}
|
|
177
146
|
|
|
178
|
-
|
|
179
|
-
if (this._element.scrollWidth - this._element.scrollLeft <= this._element.offsetWidth) {
|
|
180
|
-
this._element.scrollTo(this._slides[0].offsetLeft, 0)
|
|
181
|
-
return
|
|
182
|
-
}
|
|
147
|
+
const previous = this._current
|
|
183
148
|
|
|
184
|
-
|
|
149
|
+
let clone
|
|
185
150
|
|
|
186
|
-
|
|
187
|
-
* Go to a slide by index
|
|
188
|
-
*
|
|
189
|
-
* @param {int} index - The index number of the slide
|
|
190
|
-
*/
|
|
191
|
-
goTo(index) {
|
|
151
|
+
if (this._options.loop && (index < 0 || index >= this._slides.length)) {
|
|
192
152
|
|
|
193
|
-
|
|
194
|
-
|
|
153
|
+
// Go to the correct slide index
|
|
154
|
+
this._current = index < 0 ? this._slides.length - 1 : 0
|
|
195
155
|
|
|
196
|
-
|
|
197
|
-
|
|
156
|
+
// If scroll behavior go to the clone offset
|
|
157
|
+
if (this._options.behavior == 'smooth') {
|
|
158
|
+
clone = this._current == 0 ? this._element.lastElementChild : this._element.firstElementChild
|
|
159
|
+
}
|
|
198
160
|
|
|
199
|
-
if (this._options.loop && (index < 0 || index > this._slides.length - 1)) {
|
|
200
|
-
offset = this._element.children[index + 1].offsetLeft
|
|
201
161
|
} else {
|
|
202
|
-
|
|
203
|
-
|
|
162
|
+
// Otherwise go to the index
|
|
163
|
+
this._current = index
|
|
204
164
|
}
|
|
205
165
|
|
|
206
|
-
//
|
|
166
|
+
// Define the offset
|
|
167
|
+
const offset = clone ? clone.offsetLeft : this._slides[this._current].offsetLeft
|
|
168
|
+
|
|
169
|
+
// Go to the slide
|
|
207
170
|
this._element.scrollTo({
|
|
208
171
|
left: offset,
|
|
209
172
|
behavior: this._options.behavior
|
|
210
173
|
})
|
|
211
174
|
|
|
175
|
+
// If clone offset, then go to the right slide instant
|
|
176
|
+
if (clone) {
|
|
177
|
+
setTimeout(() => {
|
|
178
|
+
this._element.scrollTo({
|
|
179
|
+
left: this._slides[this._current].offsetLeft,
|
|
180
|
+
behavior: 'instant'
|
|
181
|
+
})
|
|
182
|
+
}, 500)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Update the [aria-selected] attribute on tabs
|
|
186
|
+
this._buttons.tabs.forEach((tab, idx) => tab.setAttribute('aria-selected', idx === this._current))
|
|
187
|
+
|
|
188
|
+
// Update the [aria-hidden] attribute on slides
|
|
189
|
+
this._slides.forEach((slide, idx) => slide.setAttribute('aria-hidden', idx !== this._current))
|
|
190
|
+
|
|
191
|
+
// Disable next and prev buttons if necessary
|
|
192
|
+
if (this._buttons.next && !this._options.loop) {
|
|
193
|
+
this._buttons.next.disabled = this._current === this._slides.length - 1
|
|
194
|
+
}
|
|
195
|
+
if (this._buttons.prev && !this._options.loop) {
|
|
196
|
+
this._buttons.prev.disabled = this._current === 0
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Emit "changed" event after the slide has changed
|
|
200
|
+
this.emmitEvent('changed', { current: this._current, previous: previous })
|
|
212
201
|
}
|
|
213
202
|
|
|
214
203
|
/**
|
|
215
|
-
* Go to the next slide
|
|
216
|
-
*
|
|
204
|
+
* Go to the next slide.
|
|
217
205
|
*/
|
|
218
206
|
next() {
|
|
207
|
+
const nextIndex = this._current + 1
|
|
219
208
|
|
|
220
|
-
//
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
// If last item => return
|
|
224
|
-
if (!this._options.loop && !this._options.autoplay && index === this._slides.length) return
|
|
225
|
-
|
|
226
|
-
// Run method goTo()
|
|
227
|
-
this.goTo(index)
|
|
209
|
+
// Prevent scrolling if at the last slide and looping is disabled
|
|
210
|
+
if (!this._options.loop && nextIndex >= this._slides.length) return
|
|
228
211
|
|
|
212
|
+
// Move to the next slide
|
|
213
|
+
this.goTo(nextIndex)
|
|
229
214
|
}
|
|
230
215
|
|
|
231
216
|
/**
|
|
232
|
-
* Go to the previous slide
|
|
233
|
-
*
|
|
217
|
+
* Go to the previous slide.
|
|
234
218
|
*/
|
|
235
219
|
prev() {
|
|
220
|
+
const prevIndex = this._current - 1
|
|
236
221
|
|
|
237
|
-
//
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
// If first item => return
|
|
241
|
-
if (!this._options.loop && index < 0) return
|
|
242
|
-
|
|
243
|
-
// Run method goTo()
|
|
244
|
-
this.goTo(index)
|
|
222
|
+
// Prevent scrolling if at the first slide and looping is disabled
|
|
223
|
+
if (!this._options.loop && prevIndex < 0) return
|
|
245
224
|
|
|
225
|
+
// Move to the previous slide
|
|
226
|
+
this.goTo(prevIndex)
|
|
246
227
|
}
|
|
247
228
|
|
|
248
|
-
}
|
|
229
|
+
}
|
package/js/_sortable.js
CHANGED
|
@@ -26,9 +26,17 @@ export default class Sortable extends BaseComponent {
|
|
|
26
26
|
super(el, options, 'sortable')
|
|
27
27
|
|
|
28
28
|
// Define the properties
|
|
29
|
+
this._items = null
|
|
29
30
|
this._withHandle = this._element.querySelector('[data-handle=sortable]') ? true : false
|
|
30
31
|
this._current = null
|
|
31
32
|
|
|
33
|
+
// Lier une seule fois les méthodes à `this`
|
|
34
|
+
this.handleMouseDown = this.handleMouseDown.bind(this)
|
|
35
|
+
this.handleMouseUp = this.handleMouseUp.bind(this)
|
|
36
|
+
this.drag = this.drag.bind(this)
|
|
37
|
+
this.dragging = this.dragging.bind(this)
|
|
38
|
+
this.drop = this.drop.bind(this)
|
|
39
|
+
|
|
32
40
|
// Init the event listener
|
|
33
41
|
this.#init()
|
|
34
42
|
|
|
@@ -44,41 +52,88 @@ export default class Sortable extends BaseComponent {
|
|
|
44
52
|
// Prevent default animation at the drop
|
|
45
53
|
this._element.addEventListener('dragover', (e) => e.preventDefault())
|
|
46
54
|
|
|
47
|
-
//
|
|
48
|
-
this
|
|
49
|
-
|
|
50
|
-
// Toggle the [dragable] attribute
|
|
51
|
-
item.addEventListener('mousedown', (e) => { if (!this._withHandle || (e.target.hasAttribute('data-handle') && e.target.getAttribute('data-handle') === 'sortable')) item.draggable = true })
|
|
52
|
-
item.addEventListener('mouseup', () => item.draggable = false)
|
|
55
|
+
// Init the events on the items
|
|
56
|
+
this.#initEvents()
|
|
53
57
|
|
|
54
|
-
|
|
55
|
-
item.addEventListener('dragstart', () => this.#drag(item))
|
|
56
|
-
item.addEventListener('dragenter', () => this.#dragging(item))
|
|
57
|
-
item.addEventListener('dragend', () => this.#drop(item))
|
|
58
|
+
}
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Init the items and the event listeners
|
|
62
|
+
*
|
|
63
|
+
* @private
|
|
64
|
+
*/
|
|
65
|
+
#initEvents() {
|
|
66
|
+
|
|
67
|
+
// Get the items
|
|
68
|
+
this._items = this._element.querySelectorAll('[draggable]')
|
|
69
|
+
|
|
70
|
+
// Add the events
|
|
71
|
+
this._items.forEach(item => {
|
|
72
|
+
item.addEventListener('mousedown', this.handleMouseDown)
|
|
73
|
+
item.addEventListener('mouseup', this.handleMouseUp)
|
|
74
|
+
item.addEventListener('dragstart', this.drag)
|
|
75
|
+
item.addEventListener('dragenter', this.dragging)
|
|
76
|
+
item.addEventListener('dragend', this.drop)
|
|
77
|
+
})
|
|
78
|
+
}
|
|
61
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Reset the event listeners
|
|
82
|
+
*
|
|
83
|
+
* @private
|
|
84
|
+
*/
|
|
85
|
+
resetEvents() {
|
|
86
|
+
|
|
87
|
+
// Remove the listeners
|
|
88
|
+
this._items.forEach((item) => {
|
|
89
|
+
item.removeEventListener('mousedown', this.handleMouseDown)
|
|
90
|
+
item.removeEventListener('mouseup', this.handleMouseUp)
|
|
91
|
+
item.removeEventListener('dragstart', this.drag)
|
|
92
|
+
item.removeEventListener('dragenter', this.dragging)
|
|
93
|
+
item.removeEventListener('dragend', this.drop)
|
|
62
94
|
})
|
|
63
95
|
|
|
96
|
+
// Re-initialise the items
|
|
97
|
+
this.#initEvents()
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Handle the mousedown event
|
|
102
|
+
*
|
|
103
|
+
* @private
|
|
104
|
+
*/
|
|
105
|
+
handleMouseDown(e) {
|
|
106
|
+
// Avoid if not an element
|
|
107
|
+
if (!(e.target instanceof Element)) return
|
|
108
|
+
const target = e.target.closest('[draggable]')
|
|
109
|
+
if (!this._withHandle || (e.target.hasAttribute('data-handle') && e.target.getAttribute('data-handle') === 'sortable')) target.draggable = true
|
|
64
110
|
}
|
|
65
111
|
|
|
66
112
|
/**
|
|
67
|
-
*
|
|
113
|
+
* Handle the mouseup event
|
|
68
114
|
*
|
|
69
|
-
* @
|
|
115
|
+
* @private
|
|
70
116
|
*/
|
|
71
|
-
|
|
72
|
-
|
|
117
|
+
handleMouseUp(e) {
|
|
118
|
+
// Avoid if not an element
|
|
119
|
+
if (!(e.target instanceof Element)) return
|
|
120
|
+
const target = e.target.closest('[draggable]')
|
|
121
|
+
target.draggable = false
|
|
73
122
|
}
|
|
74
123
|
|
|
75
124
|
/**
|
|
76
125
|
* Drag an item
|
|
77
126
|
*
|
|
78
|
-
* @param {HTMLElement} item - The current item
|
|
79
127
|
* @private
|
|
80
128
|
*/
|
|
81
|
-
|
|
129
|
+
drag(e) {
|
|
130
|
+
|
|
131
|
+
// Avoid if not an element
|
|
132
|
+
if (!(e.target instanceof Element)) return
|
|
133
|
+
|
|
134
|
+
// Get the item
|
|
135
|
+
// * Bug with event listeners reset if passing some data
|
|
136
|
+
const item = e.target.closest('[draggable]')
|
|
82
137
|
|
|
83
138
|
// Check for errors
|
|
84
139
|
if (!(item instanceof HTMLElement)) throw new Error(ErrorMessage.instanceOf('item', 'HTMLElement'))
|
|
@@ -100,10 +155,16 @@ export default class Sortable extends BaseComponent {
|
|
|
100
155
|
/**
|
|
101
156
|
* When dragging an item, move it before or after an element
|
|
102
157
|
*
|
|
103
|
-
* @param {HTMLElement} item - The current item
|
|
104
158
|
* @private
|
|
105
159
|
*/
|
|
106
|
-
|
|
160
|
+
dragging(e) {
|
|
161
|
+
|
|
162
|
+
// Avoid if not an element
|
|
163
|
+
if (!(e.target instanceof Element)) return
|
|
164
|
+
|
|
165
|
+
// Get the item
|
|
166
|
+
// * Bug with event listeners reset if passing some data
|
|
167
|
+
const item = e.target.closest('[draggable]')
|
|
107
168
|
|
|
108
169
|
// Check for errors
|
|
109
170
|
if (!(item instanceof HTMLElement)) throw new Error(ErrorMessage.instanceOf('item', 'HTMLElement'))
|
|
@@ -120,10 +181,16 @@ export default class Sortable extends BaseComponent {
|
|
|
120
181
|
/**
|
|
121
182
|
* Drop an item
|
|
122
183
|
*
|
|
123
|
-
* @param {HTMLElement} item - The current item
|
|
124
184
|
* @private
|
|
125
185
|
*/
|
|
126
|
-
|
|
186
|
+
drop(e) {
|
|
187
|
+
|
|
188
|
+
// Avoid if not an element
|
|
189
|
+
if (!(e.target instanceof Element)) return
|
|
190
|
+
|
|
191
|
+
// Get the item
|
|
192
|
+
// * Bug with event listeners reset if passing some data
|
|
193
|
+
const item = e.target.closest('[draggable]')
|
|
127
194
|
|
|
128
195
|
// Check for errors
|
|
129
196
|
if (!(item instanceof HTMLElement)) throw new Error(ErrorMessage.instanceOf('item', 'HTMLElement'))
|
|
@@ -145,26 +212,4 @@ export default class Sortable extends BaseComponent {
|
|
|
145
212
|
|
|
146
213
|
}
|
|
147
214
|
|
|
148
|
-
/**
|
|
149
|
-
* Manually move up and down
|
|
150
|
-
*
|
|
151
|
-
* @param {HTMLElement} item - The current item
|
|
152
|
-
* @private
|
|
153
|
-
*/
|
|
154
|
-
#move(item, goUp = false) {
|
|
155
|
-
|
|
156
|
-
const sibling = goUp ? item.previousElementSibling : item.nextElementSibling
|
|
157
|
-
|
|
158
|
-
if (sibling) {
|
|
159
|
-
this._element.insertBefore(item, goUp ? sibling : sibling.nextElementSibling)
|
|
160
|
-
} else if (!goUp) {
|
|
161
|
-
this._element.appendChild(item)
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Run custom event
|
|
165
|
-
this.emmitEvent('moved', { items: this.items, current: item })
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
|
|
170
215
|
}
|