@doyosi/laraisy 1.0.2 → 1.0.3
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/LICENSE +1 -1
- package/package.json +1 -1
- package/src/CodeInput.js +48 -48
- package/src/DSAlert.js +352 -352
- package/src/DSAvatar.js +207 -207
- package/src/DSDelete.js +274 -274
- package/src/DSForm.js +568 -568
- package/src/DSGridOrTable.js +453 -453
- package/src/DSLocaleSwitcher.js +239 -239
- package/src/DSLogout.js +293 -293
- package/src/DSNotifications.js +365 -365
- package/src/DSRestore.js +181 -181
- package/src/DSSelect.js +1071 -1071
- package/src/DSSelectBox.js +563 -563
- package/src/DSSimpleSlider.js +517 -517
- package/src/DSSvgFetch.js +69 -69
- package/src/DSTable/DSTableExport.js +68 -68
- package/src/DSTable/DSTableFilter.js +224 -224
- package/src/DSTable/DSTablePagination.js +136 -136
- package/src/DSTable/DSTableSearch.js +40 -40
- package/src/DSTable/DSTableSelection.js +192 -192
- package/src/DSTable/DSTableSort.js +58 -58
- package/src/DSTable.js +353 -353
- package/src/DSTabs.js +488 -488
- package/src/DSUpload.js +887 -887
- package/dist/CodeInput.d.ts +0 -10
- package/dist/DSAlert.d.ts +0 -112
- package/dist/DSAvatar.d.ts +0 -45
- package/dist/DSDelete.d.ts +0 -61
- package/dist/DSForm.d.ts +0 -151
- package/dist/DSGridOrTable/DSGOTRenderer.d.ts +0 -60
- package/dist/DSGridOrTable/DSGOTViewToggle.d.ts +0 -26
- package/dist/DSGridOrTable.d.ts +0 -296
- package/dist/DSLocaleSwitcher.d.ts +0 -71
- package/dist/DSLogout.d.ts +0 -76
- package/dist/DSNotifications.d.ts +0 -54
- package/dist/DSRestore.d.ts +0 -56
- package/dist/DSSelect.d.ts +0 -221
- package/dist/DSSelectBox.d.ts +0 -123
- package/dist/DSSimpleSlider.d.ts +0 -136
- package/dist/DSSvgFetch.d.ts +0 -17
- package/dist/DSTable/DSTableExport.d.ts +0 -11
- package/dist/DSTable/DSTableFilter.d.ts +0 -40
- package/dist/DSTable/DSTablePagination.d.ts +0 -12
- package/dist/DSTable/DSTableSearch.d.ts +0 -8
- package/dist/DSTable/DSTableSelection.d.ts +0 -46
- package/dist/DSTable/DSTableSort.d.ts +0 -8
- package/dist/DSTable.d.ts +0 -116
- package/dist/DSTabs.d.ts +0 -156
- package/dist/DSUpload.d.ts +0 -220
- package/dist/index.d.ts +0 -17
package/src/DSSimpleSlider.js
CHANGED
|
@@ -1,517 +1,517 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DSSimpleSlider
|
|
3
|
-
*
|
|
4
|
-
* A flexible, customizable slider plugin supporting multiple data sources
|
|
5
|
-
* (ajax, json, html) with auto-play, hover pause, and timer border animation.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* // AJAX Mode
|
|
9
|
-
* const slider = new DSSimpleSlider('#premiumSlider', {
|
|
10
|
-
* source: 'ajax',
|
|
11
|
-
* ajax_url: '/api/featured-domains',
|
|
12
|
-
* ajax_method: 'GET',
|
|
13
|
-
* autoPlay: true,
|
|
14
|
-
* interval: 5000,
|
|
15
|
-
* pauseOnHover: true
|
|
16
|
-
* });
|
|
17
|
-
*
|
|
18
|
-
* // JSON Mode
|
|
19
|
-
* const slider = new DSSimpleSlider('#slider', {
|
|
20
|
-
* source: 'json',
|
|
21
|
-
* data: [
|
|
22
|
-
* { title: 'crypto.com', subtitle: '$12,000' },
|
|
23
|
-
* { title: 'ai.io', subtitle: '$8,500' }
|
|
24
|
-
* ]
|
|
25
|
-
* });
|
|
26
|
-
*
|
|
27
|
-
* // HTML Mode (reads existing content)
|
|
28
|
-
* const slider = new DSSimpleSlider('#slider', { source: 'html' });
|
|
29
|
-
*/
|
|
30
|
-
class DSSimpleSlider {
|
|
31
|
-
static defaults = {
|
|
32
|
-
// Data source: 'ajax', 'json', 'html'
|
|
33
|
-
source: 'json',
|
|
34
|
-
|
|
35
|
-
// AJAX settings
|
|
36
|
-
ajax_url: null,
|
|
37
|
-
ajax_method: 'GET',
|
|
38
|
-
ajax_data: {},
|
|
39
|
-
ajax_function: 'axios', // 'axios', 'fetch', 'xhr'
|
|
40
|
-
|
|
41
|
-
// JSON data (for source: 'json')
|
|
42
|
-
data: [],
|
|
43
|
-
|
|
44
|
-
// Data mapping (how to extract title/subtitle from data)
|
|
45
|
-
dataMap: {
|
|
46
|
-
title: 'title', // property name for title
|
|
47
|
-
subtitle: 'subtitle', // property name for subtitle
|
|
48
|
-
url: 'url' // property name for link URL (optional)
|
|
49
|
-
},
|
|
50
|
-
|
|
51
|
-
// Auto-play settings
|
|
52
|
-
autoPlay: true,
|
|
53
|
-
interval: 5000, // ms between slides
|
|
54
|
-
pauseOnHover: true,
|
|
55
|
-
|
|
56
|
-
// Timer border animation
|
|
57
|
-
showTimerBorder: true, // set to false to disable
|
|
58
|
-
timerBorderSelector: '.ds-slider-badge', // element to animate border
|
|
59
|
-
timerBorderColor: 'rgba(251, 191, 36, 1)', // amber-400
|
|
60
|
-
timerBorderWidth: 2,
|
|
61
|
-
|
|
62
|
-
// Navigation buttons
|
|
63
|
-
showPrevButton: true,
|
|
64
|
-
showNextButton: true,
|
|
65
|
-
prevButtonSelector: '.ds-slider-prev',
|
|
66
|
-
nextButtonSelector: '.ds-slider-next',
|
|
67
|
-
|
|
68
|
-
// Content selectors
|
|
69
|
-
contentSelector: '.ds-slider-content',
|
|
70
|
-
titleSelector: '.ds-slider-title',
|
|
71
|
-
subtitleSelector: '.ds-slider-subtitle',
|
|
72
|
-
|
|
73
|
-
// Disabled state
|
|
74
|
-
disabledClass: 'opacity-50 pointer-events-none',
|
|
75
|
-
|
|
76
|
-
// Animation
|
|
77
|
-
fadeClass: 'transition-opacity duration-300',
|
|
78
|
-
|
|
79
|
-
// Callbacks
|
|
80
|
-
onSlideChange: null,
|
|
81
|
-
onDataLoad: null,
|
|
82
|
-
onEmpty: null
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
constructor(wrapper, options = {}) {
|
|
86
|
-
this.wrapper = typeof wrapper === 'string' ? document.querySelector(wrapper) : wrapper;
|
|
87
|
-
if (!this.wrapper) {
|
|
88
|
-
console.warn('DSSimpleSlider: Wrapper element not found');
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
this.config = { ...DSSimpleSlider.defaults, ...options };
|
|
93
|
-
this.slides = [];
|
|
94
|
-
this.currentIndex = 0;
|
|
95
|
-
this.isPlaying = false;
|
|
96
|
-
this.isPaused = false;
|
|
97
|
-
this.timer = null;
|
|
98
|
-
this.timerAnimation = null;
|
|
99
|
-
|
|
100
|
-
this._init();
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
async _init() {
|
|
104
|
-
this._cacheElements();
|
|
105
|
-
await this._loadData();
|
|
106
|
-
this._bindEvents();
|
|
107
|
-
|
|
108
|
-
if (this.slides.length > 0) {
|
|
109
|
-
this._render();
|
|
110
|
-
if (this.config.autoPlay) {
|
|
111
|
-
this.play();
|
|
112
|
-
}
|
|
113
|
-
} else {
|
|
114
|
-
this._handleEmpty();
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
_cacheElements() {
|
|
119
|
-
this.contentEl = this.wrapper.querySelector(this.config.contentSelector);
|
|
120
|
-
this.titleEl = this.wrapper.querySelector(this.config.titleSelector);
|
|
121
|
-
this.subtitleEl = this.wrapper.querySelector(this.config.subtitleSelector);
|
|
122
|
-
this.prevBtn = this.wrapper.querySelector(this.config.prevButtonSelector);
|
|
123
|
-
this.nextBtn = this.wrapper.querySelector(this.config.nextButtonSelector);
|
|
124
|
-
this.badgeEl = this.wrapper.querySelector(this.config.timerBorderSelector);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
async _loadData() {
|
|
128
|
-
try {
|
|
129
|
-
switch (this.config.source) {
|
|
130
|
-
case 'ajax':
|
|
131
|
-
await this._loadFromAjax();
|
|
132
|
-
break;
|
|
133
|
-
case 'json':
|
|
134
|
-
this.slides = this.config.data || [];
|
|
135
|
-
break;
|
|
136
|
-
case 'html':
|
|
137
|
-
this._loadFromHtml();
|
|
138
|
-
break;
|
|
139
|
-
default:
|
|
140
|
-
this.slides = [];
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (this.config.onDataLoad) {
|
|
144
|
-
this.config.onDataLoad(this.slides);
|
|
145
|
-
}
|
|
146
|
-
} catch (error) {
|
|
147
|
-
console.error('DSSimpleSlider: Error loading data', error);
|
|
148
|
-
this.slides = [];
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
async _loadFromAjax() {
|
|
153
|
-
const { ajax_url, ajax_method, ajax_data, ajax_function } = this.config;
|
|
154
|
-
|
|
155
|
-
if (!ajax_url) {
|
|
156
|
-
console.warn('DSSimpleSlider: ajax_url is required for ajax source');
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
try {
|
|
161
|
-
let response;
|
|
162
|
-
|
|
163
|
-
if (ajax_function === 'axios' && window.axios) {
|
|
164
|
-
response = await window.axios({
|
|
165
|
-
method: ajax_method,
|
|
166
|
-
url: ajax_url,
|
|
167
|
-
params: ajax_method === 'GET' ? ajax_data : undefined,
|
|
168
|
-
data: ajax_method !== 'GET' ? ajax_data : undefined
|
|
169
|
-
});
|
|
170
|
-
this.slides = response.data?.data || response.data || [];
|
|
171
|
-
} else if (ajax_function === 'fetch' || window.fetch) {
|
|
172
|
-
const queryString = new URLSearchParams(ajax_data).toString();
|
|
173
|
-
const fetchUrl = ajax_method === 'GET' && queryString ? `${ajax_url}?${queryString}` : ajax_url;
|
|
174
|
-
const options = {
|
|
175
|
-
method: ajax_method,
|
|
176
|
-
headers: { 'Accept': 'application/json' }
|
|
177
|
-
};
|
|
178
|
-
if (ajax_method !== 'GET') {
|
|
179
|
-
options.headers['Content-Type'] = 'application/json';
|
|
180
|
-
options.body = JSON.stringify(ajax_data);
|
|
181
|
-
}
|
|
182
|
-
const res = await fetch(fetchUrl, options);
|
|
183
|
-
const json = await res.json();
|
|
184
|
-
this.slides = json?.data || json || [];
|
|
185
|
-
} else {
|
|
186
|
-
// XHR fallback
|
|
187
|
-
this.slides = await this._loadFromXhr();
|
|
188
|
-
}
|
|
189
|
-
} catch (error) {
|
|
190
|
-
console.error('DSSimpleSlider: AJAX error', error);
|
|
191
|
-
this.slides = [];
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
_loadFromXhr() {
|
|
196
|
-
return new Promise((resolve, reject) => {
|
|
197
|
-
const { ajax_url, ajax_method, ajax_data } = this.config;
|
|
198
|
-
const xhr = new XMLHttpRequest();
|
|
199
|
-
|
|
200
|
-
let url = ajax_url;
|
|
201
|
-
if (ajax_method === 'GET' && Object.keys(ajax_data).length) {
|
|
202
|
-
url += '?' + new URLSearchParams(ajax_data).toString();
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
xhr.open(ajax_method, url, true);
|
|
206
|
-
xhr.setRequestHeader('Accept', 'application/json');
|
|
207
|
-
|
|
208
|
-
if (ajax_method !== 'GET') {
|
|
209
|
-
xhr.setRequestHeader('Content-Type', 'application/json');
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
xhr.onload = () => {
|
|
213
|
-
if (xhr.status >= 200 && xhr.status < 300) {
|
|
214
|
-
try {
|
|
215
|
-
const json = JSON.parse(xhr.responseText);
|
|
216
|
-
resolve(json?.data || json || []);
|
|
217
|
-
} catch (e) {
|
|
218
|
-
reject(e);
|
|
219
|
-
}
|
|
220
|
-
} else {
|
|
221
|
-
reject(new Error(xhr.statusText));
|
|
222
|
-
}
|
|
223
|
-
};
|
|
224
|
-
|
|
225
|
-
xhr.onerror = () => reject(new Error('Network error'));
|
|
226
|
-
xhr.send(ajax_method !== 'GET' ? JSON.stringify(ajax_data) : null);
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
_loadFromHtml() {
|
|
231
|
-
// Read existing content as the first slide
|
|
232
|
-
if (this.titleEl && this.subtitleEl) {
|
|
233
|
-
const title = this.titleEl.textContent.trim();
|
|
234
|
-
const subtitle = this.subtitleEl.textContent.trim();
|
|
235
|
-
if (title) {
|
|
236
|
-
this.slides = [{ title, subtitle }];
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
_bindEvents() {
|
|
242
|
-
// Navigation buttons
|
|
243
|
-
if (this.prevBtn && this.config.showPrevButton) {
|
|
244
|
-
this.prevBtn.addEventListener('click', (e) => {
|
|
245
|
-
e.preventDefault();
|
|
246
|
-
this.prev();
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (this.nextBtn && this.config.showNextButton) {
|
|
251
|
-
this.nextBtn.addEventListener('click', (e) => {
|
|
252
|
-
e.preventDefault();
|
|
253
|
-
this.next();
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// Hover pause
|
|
258
|
-
if (this.config.pauseOnHover) {
|
|
259
|
-
this.wrapper.addEventListener('mouseenter', () => this.pause());
|
|
260
|
-
this.wrapper.addEventListener('mouseleave', () => this.resume());
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
_render() {
|
|
265
|
-
const slide = this.slides[this.currentIndex];
|
|
266
|
-
if (!slide) return;
|
|
267
|
-
|
|
268
|
-
const { dataMap } = this.config;
|
|
269
|
-
const title = this._getNestedValue(slide, dataMap.title) || '';
|
|
270
|
-
const subtitle = this._getNestedValue(slide, dataMap.subtitle) || '';
|
|
271
|
-
const url = this._getNestedValue(slide, dataMap.url) || null;
|
|
272
|
-
|
|
273
|
-
// Apply fade effect
|
|
274
|
-
if (this.contentEl) {
|
|
275
|
-
this.contentEl.classList.add('opacity-0');
|
|
276
|
-
|
|
277
|
-
setTimeout(() => {
|
|
278
|
-
if (this.titleEl) this.titleEl.textContent = title;
|
|
279
|
-
if (this.subtitleEl) this.subtitleEl.textContent = subtitle;
|
|
280
|
-
|
|
281
|
-
// Handle URL wrapping
|
|
282
|
-
if (url && this.contentEl) {
|
|
283
|
-
this.contentEl.style.cursor = 'pointer';
|
|
284
|
-
this.contentEl.onclick = () => window.location.href = url;
|
|
285
|
-
} else if (this.contentEl) {
|
|
286
|
-
this.contentEl.style.cursor = 'default';
|
|
287
|
-
this.contentEl.onclick = null;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
this.contentEl.classList.remove('opacity-0');
|
|
291
|
-
}, 150);
|
|
292
|
-
} else {
|
|
293
|
-
if (this.titleEl) this.titleEl.textContent = title;
|
|
294
|
-
if (this.subtitleEl) this.subtitleEl.textContent = subtitle;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
// Callback
|
|
298
|
-
if (this.config.onSlideChange) {
|
|
299
|
-
this.config.onSlideChange(slide, this.currentIndex, this.slides.length);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// Emit event
|
|
303
|
-
this.wrapper.dispatchEvent(new CustomEvent('dsslider:change', {
|
|
304
|
-
detail: { slide, index: this.currentIndex, total: this.slides.length }
|
|
305
|
-
}));
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
_handleEmpty() {
|
|
309
|
-
// Disable buttons
|
|
310
|
-
if (this.prevBtn) {
|
|
311
|
-
this.prevBtn.classList.add(...this.config.disabledClass.split(' '));
|
|
312
|
-
this.prevBtn.disabled = true;
|
|
313
|
-
}
|
|
314
|
-
if (this.nextBtn) {
|
|
315
|
-
this.nextBtn.classList.add(...this.config.disabledClass.split(' '));
|
|
316
|
-
this.nextBtn.disabled = true;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
// Clear content
|
|
320
|
-
if (this.titleEl) this.titleEl.textContent = '';
|
|
321
|
-
if (this.subtitleEl) this.subtitleEl.textContent = '';
|
|
322
|
-
|
|
323
|
-
// Callback
|
|
324
|
-
if (this.config.onEmpty) {
|
|
325
|
-
this.config.onEmpty();
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
// Emit event
|
|
329
|
-
this.wrapper.dispatchEvent(new CustomEvent('dsslider:empty'));
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
_startTimer() {
|
|
333
|
-
this._stopTimer();
|
|
334
|
-
|
|
335
|
-
if (this.config.showTimerBorder && this.badgeEl) {
|
|
336
|
-
this._startTimerBorderAnimation();
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
this.timer = setTimeout(() => {
|
|
340
|
-
this.next();
|
|
341
|
-
}, this.config.interval);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
_stopTimer() {
|
|
345
|
-
if (this.timer) {
|
|
346
|
-
clearTimeout(this.timer);
|
|
347
|
-
this.timer = null;
|
|
348
|
-
}
|
|
349
|
-
this._stopTimerBorderAnimation();
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
_startTimerBorderAnimation() {
|
|
353
|
-
if (!this.badgeEl) return;
|
|
354
|
-
|
|
355
|
-
const { interval, timerBorderColor, timerBorderWidth } = this.config;
|
|
356
|
-
|
|
357
|
-
// Create a pseudo-element style for the border animation
|
|
358
|
-
// We'll use a conic gradient that animates around the element
|
|
359
|
-
this.badgeEl.style.setProperty('--timer-duration', `${interval}ms`);
|
|
360
|
-
this.badgeEl.style.setProperty('--timer-color', timerBorderColor);
|
|
361
|
-
|
|
362
|
-
// Add animation class
|
|
363
|
-
this.badgeEl.classList.add('ds-slider-timer-active');
|
|
364
|
-
|
|
365
|
-
// Reset animation by forcing reflow
|
|
366
|
-
this.badgeEl.style.animation = 'none';
|
|
367
|
-
this.badgeEl.offsetHeight; // Trigger reflow
|
|
368
|
-
this.badgeEl.style.animation = `ds-slider-timer-border ${interval}ms linear`;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
_stopTimerBorderAnimation() {
|
|
372
|
-
if (this.badgeEl) {
|
|
373
|
-
this.badgeEl.classList.remove('ds-slider-timer-active');
|
|
374
|
-
this.badgeEl.style.animation = '';
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// Public methods
|
|
379
|
-
next() {
|
|
380
|
-
if (this.slides.length === 0) return;
|
|
381
|
-
this.currentIndex = (this.currentIndex + 1) % this.slides.length;
|
|
382
|
-
this._render();
|
|
383
|
-
|
|
384
|
-
if (this.isPlaying && !this.isPaused) {
|
|
385
|
-
this._startTimer();
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
prev() {
|
|
390
|
-
if (this.slides.length === 0) return;
|
|
391
|
-
this.currentIndex = (this.currentIndex - 1 + this.slides.length) % this.slides.length;
|
|
392
|
-
this._render();
|
|
393
|
-
|
|
394
|
-
if (this.isPlaying && !this.isPaused) {
|
|
395
|
-
this._startTimer();
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
goTo(index) {
|
|
400
|
-
if (index < 0 || index >= this.slides.length) return;
|
|
401
|
-
this.currentIndex = index;
|
|
402
|
-
this._render();
|
|
403
|
-
|
|
404
|
-
if (this.isPlaying && !this.isPaused) {
|
|
405
|
-
this._startTimer();
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
play() {
|
|
410
|
-
if (this.slides.length <= 1) return;
|
|
411
|
-
this.isPlaying = true;
|
|
412
|
-
this.isPaused = false;
|
|
413
|
-
this._startTimer();
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
pause() {
|
|
417
|
-
this.isPaused = true;
|
|
418
|
-
this._stopTimer();
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
resume() {
|
|
422
|
-
if (this.isPlaying) {
|
|
423
|
-
this.isPaused = false;
|
|
424
|
-
this._startTimer();
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
stop() {
|
|
429
|
-
this.isPlaying = false;
|
|
430
|
-
this.isPaused = false;
|
|
431
|
-
this._stopTimer();
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
// Reload data
|
|
435
|
-
async reload(newData = null) {
|
|
436
|
-
if (newData) {
|
|
437
|
-
this.slides = newData;
|
|
438
|
-
} else {
|
|
439
|
-
await this._loadData();
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
this.currentIndex = 0;
|
|
443
|
-
|
|
444
|
-
if (this.slides.length > 0) {
|
|
445
|
-
this._render();
|
|
446
|
-
if (this.config.autoPlay) {
|
|
447
|
-
this.play();
|
|
448
|
-
}
|
|
449
|
-
} else {
|
|
450
|
-
this._handleEmpty();
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
// Set AJAX params and reload
|
|
455
|
-
setParams(params) {
|
|
456
|
-
this.config.ajax_data = { ...this.config.ajax_data, ...params };
|
|
457
|
-
return this;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
// Get current slide
|
|
461
|
-
getCurrentSlide() {
|
|
462
|
-
return this.slides[this.currentIndex] || null;
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
// Get all slides
|
|
466
|
-
getSlides() {
|
|
467
|
-
return this.slides;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
// Destroy
|
|
471
|
-
destroy() {
|
|
472
|
-
this.stop();
|
|
473
|
-
|
|
474
|
-
// Remove event listeners
|
|
475
|
-
if (this.prevBtn) {
|
|
476
|
-
this.prevBtn.replaceWith(this.prevBtn.cloneNode(true));
|
|
477
|
-
}
|
|
478
|
-
if (this.nextBtn) {
|
|
479
|
-
this.nextBtn.replaceWith(this.nextBtn.cloneNode(true));
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
// Remove wrapper listeners
|
|
483
|
-
this.wrapper.replaceWith(this.wrapper.cloneNode(true));
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
// Helper to get nested value from object
|
|
487
|
-
_getNestedValue(obj, path) {
|
|
488
|
-
if (!path) return obj;
|
|
489
|
-
return path.split('.').reduce((acc, part) => acc && acc[part], obj);
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
// Add CSS for timer border animation
|
|
494
|
-
if (typeof document !== 'undefined') {
|
|
495
|
-
const style = document.createElement('style');
|
|
496
|
-
style.textContent = `
|
|
497
|
-
@keyframes ds-slider-timer-border {
|
|
498
|
-
0% {
|
|
499
|
-
box-shadow: inset 0 0 0 0 var(--timer-color, rgba(251, 191, 36, 0.5));
|
|
500
|
-
}
|
|
501
|
-
100% {
|
|
502
|
-
box-shadow: inset 0 0 0 2px var(--timer-color, rgba(251, 191, 36, 0.5));
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
.ds-slider-timer-active {
|
|
507
|
-
animation: ds-slider-timer-border 5000ms linear;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
.ds-slider-content {
|
|
511
|
-
transition: opacity 0.15s ease-in-out;
|
|
512
|
-
}
|
|
513
|
-
`;
|
|
514
|
-
document.head.appendChild(style);
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
export default DSSimpleSlider;
|
|
1
|
+
/**
|
|
2
|
+
* DSSimpleSlider
|
|
3
|
+
*
|
|
4
|
+
* A flexible, customizable slider plugin supporting multiple data sources
|
|
5
|
+
* (ajax, json, html) with auto-play, hover pause, and timer border animation.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* // AJAX Mode
|
|
9
|
+
* const slider = new DSSimpleSlider('#premiumSlider', {
|
|
10
|
+
* source: 'ajax',
|
|
11
|
+
* ajax_url: '/api/featured-domains',
|
|
12
|
+
* ajax_method: 'GET',
|
|
13
|
+
* autoPlay: true,
|
|
14
|
+
* interval: 5000,
|
|
15
|
+
* pauseOnHover: true
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* // JSON Mode
|
|
19
|
+
* const slider = new DSSimpleSlider('#slider', {
|
|
20
|
+
* source: 'json',
|
|
21
|
+
* data: [
|
|
22
|
+
* { title: 'crypto.com', subtitle: '$12,000' },
|
|
23
|
+
* { title: 'ai.io', subtitle: '$8,500' }
|
|
24
|
+
* ]
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* // HTML Mode (reads existing content)
|
|
28
|
+
* const slider = new DSSimpleSlider('#slider', { source: 'html' });
|
|
29
|
+
*/
|
|
30
|
+
class DSSimpleSlider {
|
|
31
|
+
static defaults = {
|
|
32
|
+
// Data source: 'ajax', 'json', 'html'
|
|
33
|
+
source: 'json',
|
|
34
|
+
|
|
35
|
+
// AJAX settings
|
|
36
|
+
ajax_url: null,
|
|
37
|
+
ajax_method: 'GET',
|
|
38
|
+
ajax_data: {},
|
|
39
|
+
ajax_function: 'axios', // 'axios', 'fetch', 'xhr'
|
|
40
|
+
|
|
41
|
+
// JSON data (for source: 'json')
|
|
42
|
+
data: [],
|
|
43
|
+
|
|
44
|
+
// Data mapping (how to extract title/subtitle from data)
|
|
45
|
+
dataMap: {
|
|
46
|
+
title: 'title', // property name for title
|
|
47
|
+
subtitle: 'subtitle', // property name for subtitle
|
|
48
|
+
url: 'url' // property name for link URL (optional)
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
// Auto-play settings
|
|
52
|
+
autoPlay: true,
|
|
53
|
+
interval: 5000, // ms between slides
|
|
54
|
+
pauseOnHover: true,
|
|
55
|
+
|
|
56
|
+
// Timer border animation
|
|
57
|
+
showTimerBorder: true, // set to false to disable
|
|
58
|
+
timerBorderSelector: '.ds-slider-badge', // element to animate border
|
|
59
|
+
timerBorderColor: 'rgba(251, 191, 36, 1)', // amber-400
|
|
60
|
+
timerBorderWidth: 2,
|
|
61
|
+
|
|
62
|
+
// Navigation buttons
|
|
63
|
+
showPrevButton: true,
|
|
64
|
+
showNextButton: true,
|
|
65
|
+
prevButtonSelector: '.ds-slider-prev',
|
|
66
|
+
nextButtonSelector: '.ds-slider-next',
|
|
67
|
+
|
|
68
|
+
// Content selectors
|
|
69
|
+
contentSelector: '.ds-slider-content',
|
|
70
|
+
titleSelector: '.ds-slider-title',
|
|
71
|
+
subtitleSelector: '.ds-slider-subtitle',
|
|
72
|
+
|
|
73
|
+
// Disabled state
|
|
74
|
+
disabledClass: 'opacity-50 pointer-events-none',
|
|
75
|
+
|
|
76
|
+
// Animation
|
|
77
|
+
fadeClass: 'transition-opacity duration-300',
|
|
78
|
+
|
|
79
|
+
// Callbacks
|
|
80
|
+
onSlideChange: null,
|
|
81
|
+
onDataLoad: null,
|
|
82
|
+
onEmpty: null
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
constructor(wrapper, options = {}) {
|
|
86
|
+
this.wrapper = typeof wrapper === 'string' ? document.querySelector(wrapper) : wrapper;
|
|
87
|
+
if (!this.wrapper) {
|
|
88
|
+
console.warn('DSSimpleSlider: Wrapper element not found');
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
this.config = { ...DSSimpleSlider.defaults, ...options };
|
|
93
|
+
this.slides = [];
|
|
94
|
+
this.currentIndex = 0;
|
|
95
|
+
this.isPlaying = false;
|
|
96
|
+
this.isPaused = false;
|
|
97
|
+
this.timer = null;
|
|
98
|
+
this.timerAnimation = null;
|
|
99
|
+
|
|
100
|
+
this._init();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async _init() {
|
|
104
|
+
this._cacheElements();
|
|
105
|
+
await this._loadData();
|
|
106
|
+
this._bindEvents();
|
|
107
|
+
|
|
108
|
+
if (this.slides.length > 0) {
|
|
109
|
+
this._render();
|
|
110
|
+
if (this.config.autoPlay) {
|
|
111
|
+
this.play();
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
this._handleEmpty();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
_cacheElements() {
|
|
119
|
+
this.contentEl = this.wrapper.querySelector(this.config.contentSelector);
|
|
120
|
+
this.titleEl = this.wrapper.querySelector(this.config.titleSelector);
|
|
121
|
+
this.subtitleEl = this.wrapper.querySelector(this.config.subtitleSelector);
|
|
122
|
+
this.prevBtn = this.wrapper.querySelector(this.config.prevButtonSelector);
|
|
123
|
+
this.nextBtn = this.wrapper.querySelector(this.config.nextButtonSelector);
|
|
124
|
+
this.badgeEl = this.wrapper.querySelector(this.config.timerBorderSelector);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async _loadData() {
|
|
128
|
+
try {
|
|
129
|
+
switch (this.config.source) {
|
|
130
|
+
case 'ajax':
|
|
131
|
+
await this._loadFromAjax();
|
|
132
|
+
break;
|
|
133
|
+
case 'json':
|
|
134
|
+
this.slides = this.config.data || [];
|
|
135
|
+
break;
|
|
136
|
+
case 'html':
|
|
137
|
+
this._loadFromHtml();
|
|
138
|
+
break;
|
|
139
|
+
default:
|
|
140
|
+
this.slides = [];
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (this.config.onDataLoad) {
|
|
144
|
+
this.config.onDataLoad(this.slides);
|
|
145
|
+
}
|
|
146
|
+
} catch (error) {
|
|
147
|
+
console.error('DSSimpleSlider: Error loading data', error);
|
|
148
|
+
this.slides = [];
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async _loadFromAjax() {
|
|
153
|
+
const { ajax_url, ajax_method, ajax_data, ajax_function } = this.config;
|
|
154
|
+
|
|
155
|
+
if (!ajax_url) {
|
|
156
|
+
console.warn('DSSimpleSlider: ajax_url is required for ajax source');
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
let response;
|
|
162
|
+
|
|
163
|
+
if (ajax_function === 'axios' && window.axios) {
|
|
164
|
+
response = await window.axios({
|
|
165
|
+
method: ajax_method,
|
|
166
|
+
url: ajax_url,
|
|
167
|
+
params: ajax_method === 'GET' ? ajax_data : undefined,
|
|
168
|
+
data: ajax_method !== 'GET' ? ajax_data : undefined
|
|
169
|
+
});
|
|
170
|
+
this.slides = response.data?.data || response.data || [];
|
|
171
|
+
} else if (ajax_function === 'fetch' || window.fetch) {
|
|
172
|
+
const queryString = new URLSearchParams(ajax_data).toString();
|
|
173
|
+
const fetchUrl = ajax_method === 'GET' && queryString ? `${ajax_url}?${queryString}` : ajax_url;
|
|
174
|
+
const options = {
|
|
175
|
+
method: ajax_method,
|
|
176
|
+
headers: { 'Accept': 'application/json' }
|
|
177
|
+
};
|
|
178
|
+
if (ajax_method !== 'GET') {
|
|
179
|
+
options.headers['Content-Type'] = 'application/json';
|
|
180
|
+
options.body = JSON.stringify(ajax_data);
|
|
181
|
+
}
|
|
182
|
+
const res = await fetch(fetchUrl, options);
|
|
183
|
+
const json = await res.json();
|
|
184
|
+
this.slides = json?.data || json || [];
|
|
185
|
+
} else {
|
|
186
|
+
// XHR fallback
|
|
187
|
+
this.slides = await this._loadFromXhr();
|
|
188
|
+
}
|
|
189
|
+
} catch (error) {
|
|
190
|
+
console.error('DSSimpleSlider: AJAX error', error);
|
|
191
|
+
this.slides = [];
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
_loadFromXhr() {
|
|
196
|
+
return new Promise((resolve, reject) => {
|
|
197
|
+
const { ajax_url, ajax_method, ajax_data } = this.config;
|
|
198
|
+
const xhr = new XMLHttpRequest();
|
|
199
|
+
|
|
200
|
+
let url = ajax_url;
|
|
201
|
+
if (ajax_method === 'GET' && Object.keys(ajax_data).length) {
|
|
202
|
+
url += '?' + new URLSearchParams(ajax_data).toString();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
xhr.open(ajax_method, url, true);
|
|
206
|
+
xhr.setRequestHeader('Accept', 'application/json');
|
|
207
|
+
|
|
208
|
+
if (ajax_method !== 'GET') {
|
|
209
|
+
xhr.setRequestHeader('Content-Type', 'application/json');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
xhr.onload = () => {
|
|
213
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
214
|
+
try {
|
|
215
|
+
const json = JSON.parse(xhr.responseText);
|
|
216
|
+
resolve(json?.data || json || []);
|
|
217
|
+
} catch (e) {
|
|
218
|
+
reject(e);
|
|
219
|
+
}
|
|
220
|
+
} else {
|
|
221
|
+
reject(new Error(xhr.statusText));
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
xhr.onerror = () => reject(new Error('Network error'));
|
|
226
|
+
xhr.send(ajax_method !== 'GET' ? JSON.stringify(ajax_data) : null);
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
_loadFromHtml() {
|
|
231
|
+
// Read existing content as the first slide
|
|
232
|
+
if (this.titleEl && this.subtitleEl) {
|
|
233
|
+
const title = this.titleEl.textContent.trim();
|
|
234
|
+
const subtitle = this.subtitleEl.textContent.trim();
|
|
235
|
+
if (title) {
|
|
236
|
+
this.slides = [{ title, subtitle }];
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
_bindEvents() {
|
|
242
|
+
// Navigation buttons
|
|
243
|
+
if (this.prevBtn && this.config.showPrevButton) {
|
|
244
|
+
this.prevBtn.addEventListener('click', (e) => {
|
|
245
|
+
e.preventDefault();
|
|
246
|
+
this.prev();
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (this.nextBtn && this.config.showNextButton) {
|
|
251
|
+
this.nextBtn.addEventListener('click', (e) => {
|
|
252
|
+
e.preventDefault();
|
|
253
|
+
this.next();
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Hover pause
|
|
258
|
+
if (this.config.pauseOnHover) {
|
|
259
|
+
this.wrapper.addEventListener('mouseenter', () => this.pause());
|
|
260
|
+
this.wrapper.addEventListener('mouseleave', () => this.resume());
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
_render() {
|
|
265
|
+
const slide = this.slides[this.currentIndex];
|
|
266
|
+
if (!slide) return;
|
|
267
|
+
|
|
268
|
+
const { dataMap } = this.config;
|
|
269
|
+
const title = this._getNestedValue(slide, dataMap.title) || '';
|
|
270
|
+
const subtitle = this._getNestedValue(slide, dataMap.subtitle) || '';
|
|
271
|
+
const url = this._getNestedValue(slide, dataMap.url) || null;
|
|
272
|
+
|
|
273
|
+
// Apply fade effect
|
|
274
|
+
if (this.contentEl) {
|
|
275
|
+
this.contentEl.classList.add('opacity-0');
|
|
276
|
+
|
|
277
|
+
setTimeout(() => {
|
|
278
|
+
if (this.titleEl) this.titleEl.textContent = title;
|
|
279
|
+
if (this.subtitleEl) this.subtitleEl.textContent = subtitle;
|
|
280
|
+
|
|
281
|
+
// Handle URL wrapping
|
|
282
|
+
if (url && this.contentEl) {
|
|
283
|
+
this.contentEl.style.cursor = 'pointer';
|
|
284
|
+
this.contentEl.onclick = () => window.location.href = url;
|
|
285
|
+
} else if (this.contentEl) {
|
|
286
|
+
this.contentEl.style.cursor = 'default';
|
|
287
|
+
this.contentEl.onclick = null;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
this.contentEl.classList.remove('opacity-0');
|
|
291
|
+
}, 150);
|
|
292
|
+
} else {
|
|
293
|
+
if (this.titleEl) this.titleEl.textContent = title;
|
|
294
|
+
if (this.subtitleEl) this.subtitleEl.textContent = subtitle;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Callback
|
|
298
|
+
if (this.config.onSlideChange) {
|
|
299
|
+
this.config.onSlideChange(slide, this.currentIndex, this.slides.length);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Emit event
|
|
303
|
+
this.wrapper.dispatchEvent(new CustomEvent('dsslider:change', {
|
|
304
|
+
detail: { slide, index: this.currentIndex, total: this.slides.length }
|
|
305
|
+
}));
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
_handleEmpty() {
|
|
309
|
+
// Disable buttons
|
|
310
|
+
if (this.prevBtn) {
|
|
311
|
+
this.prevBtn.classList.add(...this.config.disabledClass.split(' '));
|
|
312
|
+
this.prevBtn.disabled = true;
|
|
313
|
+
}
|
|
314
|
+
if (this.nextBtn) {
|
|
315
|
+
this.nextBtn.classList.add(...this.config.disabledClass.split(' '));
|
|
316
|
+
this.nextBtn.disabled = true;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Clear content
|
|
320
|
+
if (this.titleEl) this.titleEl.textContent = '';
|
|
321
|
+
if (this.subtitleEl) this.subtitleEl.textContent = '';
|
|
322
|
+
|
|
323
|
+
// Callback
|
|
324
|
+
if (this.config.onEmpty) {
|
|
325
|
+
this.config.onEmpty();
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Emit event
|
|
329
|
+
this.wrapper.dispatchEvent(new CustomEvent('dsslider:empty'));
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
_startTimer() {
|
|
333
|
+
this._stopTimer();
|
|
334
|
+
|
|
335
|
+
if (this.config.showTimerBorder && this.badgeEl) {
|
|
336
|
+
this._startTimerBorderAnimation();
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
this.timer = setTimeout(() => {
|
|
340
|
+
this.next();
|
|
341
|
+
}, this.config.interval);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
_stopTimer() {
|
|
345
|
+
if (this.timer) {
|
|
346
|
+
clearTimeout(this.timer);
|
|
347
|
+
this.timer = null;
|
|
348
|
+
}
|
|
349
|
+
this._stopTimerBorderAnimation();
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
_startTimerBorderAnimation() {
|
|
353
|
+
if (!this.badgeEl) return;
|
|
354
|
+
|
|
355
|
+
const { interval, timerBorderColor, timerBorderWidth } = this.config;
|
|
356
|
+
|
|
357
|
+
// Create a pseudo-element style for the border animation
|
|
358
|
+
// We'll use a conic gradient that animates around the element
|
|
359
|
+
this.badgeEl.style.setProperty('--timer-duration', `${interval}ms`);
|
|
360
|
+
this.badgeEl.style.setProperty('--timer-color', timerBorderColor);
|
|
361
|
+
|
|
362
|
+
// Add animation class
|
|
363
|
+
this.badgeEl.classList.add('ds-slider-timer-active');
|
|
364
|
+
|
|
365
|
+
// Reset animation by forcing reflow
|
|
366
|
+
this.badgeEl.style.animation = 'none';
|
|
367
|
+
this.badgeEl.offsetHeight; // Trigger reflow
|
|
368
|
+
this.badgeEl.style.animation = `ds-slider-timer-border ${interval}ms linear`;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
_stopTimerBorderAnimation() {
|
|
372
|
+
if (this.badgeEl) {
|
|
373
|
+
this.badgeEl.classList.remove('ds-slider-timer-active');
|
|
374
|
+
this.badgeEl.style.animation = '';
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Public methods
|
|
379
|
+
next() {
|
|
380
|
+
if (this.slides.length === 0) return;
|
|
381
|
+
this.currentIndex = (this.currentIndex + 1) % this.slides.length;
|
|
382
|
+
this._render();
|
|
383
|
+
|
|
384
|
+
if (this.isPlaying && !this.isPaused) {
|
|
385
|
+
this._startTimer();
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
prev() {
|
|
390
|
+
if (this.slides.length === 0) return;
|
|
391
|
+
this.currentIndex = (this.currentIndex - 1 + this.slides.length) % this.slides.length;
|
|
392
|
+
this._render();
|
|
393
|
+
|
|
394
|
+
if (this.isPlaying && !this.isPaused) {
|
|
395
|
+
this._startTimer();
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
goTo(index) {
|
|
400
|
+
if (index < 0 || index >= this.slides.length) return;
|
|
401
|
+
this.currentIndex = index;
|
|
402
|
+
this._render();
|
|
403
|
+
|
|
404
|
+
if (this.isPlaying && !this.isPaused) {
|
|
405
|
+
this._startTimer();
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
play() {
|
|
410
|
+
if (this.slides.length <= 1) return;
|
|
411
|
+
this.isPlaying = true;
|
|
412
|
+
this.isPaused = false;
|
|
413
|
+
this._startTimer();
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
pause() {
|
|
417
|
+
this.isPaused = true;
|
|
418
|
+
this._stopTimer();
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
resume() {
|
|
422
|
+
if (this.isPlaying) {
|
|
423
|
+
this.isPaused = false;
|
|
424
|
+
this._startTimer();
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
stop() {
|
|
429
|
+
this.isPlaying = false;
|
|
430
|
+
this.isPaused = false;
|
|
431
|
+
this._stopTimer();
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Reload data
|
|
435
|
+
async reload(newData = null) {
|
|
436
|
+
if (newData) {
|
|
437
|
+
this.slides = newData;
|
|
438
|
+
} else {
|
|
439
|
+
await this._loadData();
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
this.currentIndex = 0;
|
|
443
|
+
|
|
444
|
+
if (this.slides.length > 0) {
|
|
445
|
+
this._render();
|
|
446
|
+
if (this.config.autoPlay) {
|
|
447
|
+
this.play();
|
|
448
|
+
}
|
|
449
|
+
} else {
|
|
450
|
+
this._handleEmpty();
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Set AJAX params and reload
|
|
455
|
+
setParams(params) {
|
|
456
|
+
this.config.ajax_data = { ...this.config.ajax_data, ...params };
|
|
457
|
+
return this;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// Get current slide
|
|
461
|
+
getCurrentSlide() {
|
|
462
|
+
return this.slides[this.currentIndex] || null;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Get all slides
|
|
466
|
+
getSlides() {
|
|
467
|
+
return this.slides;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// Destroy
|
|
471
|
+
destroy() {
|
|
472
|
+
this.stop();
|
|
473
|
+
|
|
474
|
+
// Remove event listeners
|
|
475
|
+
if (this.prevBtn) {
|
|
476
|
+
this.prevBtn.replaceWith(this.prevBtn.cloneNode(true));
|
|
477
|
+
}
|
|
478
|
+
if (this.nextBtn) {
|
|
479
|
+
this.nextBtn.replaceWith(this.nextBtn.cloneNode(true));
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Remove wrapper listeners
|
|
483
|
+
this.wrapper.replaceWith(this.wrapper.cloneNode(true));
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Helper to get nested value from object
|
|
487
|
+
_getNestedValue(obj, path) {
|
|
488
|
+
if (!path) return obj;
|
|
489
|
+
return path.split('.').reduce((acc, part) => acc && acc[part], obj);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// Add CSS for timer border animation
|
|
494
|
+
if (typeof document !== 'undefined') {
|
|
495
|
+
const style = document.createElement('style');
|
|
496
|
+
style.textContent = `
|
|
497
|
+
@keyframes ds-slider-timer-border {
|
|
498
|
+
0% {
|
|
499
|
+
box-shadow: inset 0 0 0 0 var(--timer-color, rgba(251, 191, 36, 0.5));
|
|
500
|
+
}
|
|
501
|
+
100% {
|
|
502
|
+
box-shadow: inset 0 0 0 2px var(--timer-color, rgba(251, 191, 36, 0.5));
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
.ds-slider-timer-active {
|
|
507
|
+
animation: ds-slider-timer-border 5000ms linear;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
.ds-slider-content {
|
|
511
|
+
transition: opacity 0.15s ease-in-out;
|
|
512
|
+
}
|
|
513
|
+
`;
|
|
514
|
+
document.head.appendChild(style);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
export default DSSimpleSlider;
|