PageSourceSearch

https://missmaggiemayhem.com/assets/js/root/tweenslide.js?v=2

js missmaggiemayhem.com collected 2026-09-26 10:40:29 UTC 14,149 bytes, 345 lines download raw bytes

1class TweenSlide {
2    constructor(options) {
3        var containerId = options.containerId.replace(/#/g, "");
4        this.selectedContainer = options.innerSelectedContainer !== undefined ? document.getElementById(containerId).querySelector(options.innerSelectedContainer) : document.getElementById(containerId);
5        this.tweenContainer = this.selectedContainer.querySelector('.tween-container');
6        this.leftBtn = this.selectedContainer.querySelector('.left-btn');
7        this.rightBtn = this.selectedContainer.querySelector('.right-btn');
8        this.contentName = '.tween-box';
9        this.animationDelay = options.animationDelay || 3000;
10        this.animationDuration = options.animationDuration || 300;
11        this.autoSlide = options.autoSlide !== undefined ? options.autoSlide : true;
12        this.swipeMode = options.swipeMode !== undefined ? options.swipeMode : false;
13        this.infiniteMode = options.infiniteMode !== undefined ? options.infiniteMode : true;
14        if (!this.infiniteMode) {
15            this.autoSlide = false;
16            this.swipeMode = false;
17        }
18        this.totalDisplay = options.totalDisplay || 4;
19        this.slideTimeout = null;
20        this.itemWidth = 0;
21        this.lastClientX = 0;
22        this.isDragging = false;
23        this.isArea = false;
24        this.isSchedule = false;
25        this.isAnimating = false;
26        this.init();
27    }
28
29    init() {
30        const firstItem = this.tweenContainer.querySelector(this.contentName);
31        if (!firstItem) return;
32        this.itemWidth = firstItem.offsetWidth;
33        this._bindEvents();
34        this.controlSlide(true);
35        this._updateButtonsState();
36    }
37
38    getLeft() {
39        return parseInt(this.tweenContainer.style.left) || 0;
40    }
41
42    setLeft(value) {
43        this.tweenContainer.style.left = value + 'px';
44    }
45
46    getMinLeft() {
47        return -this.itemWidth * (this._getTotalItems() - this.totalDisplay);
48    }
49
50    getMaxLeft() {
51        return 0;
52    }
53
54    _updateButtonsState() {
55        if (this.infiniteMode) return;
56        const currentLeft = this.getLeft();
57        const totalItems = this._getTotalItems();
58        const currentIndex = Math.round(Math.abs(currentLeft) / this.itemWidth);
59        const isAtFirst = currentIndex <= 0;
60        const isAtLast = currentIndex >= totalItems - this.totalDisplay;
61        if (this.leftBtn) {
62            if (isAtFirst) {
63                this.leftBtn.classList.add('inactive');
64            } else {
65                this.leftBtn.classList.remove('inactive');
66            }
67        }
68        if (this.rightBtn) {
69            if (isAtLast) {
70                this.rightBtn.classList.add('inactive');
71            } else {
72                this.rightBtn.classList.remove('inactive');
73            }
74        }
75    }
76
77    applyRubberBand(value) {
78        const maxLeft = this.getMaxLeft();
79        const minLeft = this.getMinLeft();
80        if (value > maxLeft) {
81            const overpull = value - maxLeft;
82            const limitedOverpull = Math.min(overpull, 100);
83            const resistedPull = limitedOverpull * 1;
84            return maxLeft + resistedPull;
85        } else if (value < minLeft) {
86            const overpull = minLeft - value;
87            const limitedOverpull = Math.min(overpull, 100);
88            const resistedPull = limitedOverpull * 1;
89            return minLeft - resistedPull;
90        }
91        return value;
92    }
93
94    animateTo(targetLeft, duration, callback) {
95        const startLeft = this.getLeft();
96        const diff = targetLeft - startLeft;
97        const startTime = performance.now();
98        const step = function (now) {
99            const elapsed = now - startTime;
100            const progress = Math.min(elapsed / duration, 1);
101            const eased = 1 - Math.pow(1 - progress, 3);
102            this.setLeft(startLeft + diff * eased);
103            if (progress < 1) {
104                requestAnimationFrame(step);
105            } else {
106                this.setLeft(targetLeft);
107                if (callback) callback();
108                this._updateButtonsState();
109            }
110        }.bind(this);
111        requestAnimationFrame(step);
112    }
113
114    controlSlide(run) {
115        this.tweenContainer.querySelectorAll(this.contentName)
116            .forEach(function (el) { el.style.pointerEvents = ''; });
117        if (run && this._getTotalItems() > this.totalDisplay && this.autoSlide) {
118            if (!this.isArea && !this.isDragging && !this.isSchedule && this.animationDelay > 0) {
119                this.isSchedule = true;
120                clearInterval(this.slideTimeout);
121                this.slideTimeout = setInterval(
122                    function () { this.slide(this.animationDuration); }.bind(this),
123                    this.animationDelay
124                );
125            }
126        } else {
127            this.isSchedule = false;
128            clearInterval(this.slideTimeout);
129        }
130    }
131
132    slide(duration) {
133        if (this.isAnimating) return;
134        if (!this.infiniteMode) {
135            return;
136        }
137        this.isAnimating = true;
138        this.animateTo(-this.itemWidth, duration, function () {
139            this._shiftFirst();
140            this.setLeft(0);
141            this.isAnimating = false;
142        }.bind(this));
143    }
144
145    _shiftFirst() {
146        const first = this.tweenContainer.querySelector(this.contentName);
147        this.tweenContainer.appendChild(first);
148        this.setLeft(0);
149    }
150
151    _shiftLast() {
152        const items = this.tweenContainer.querySelectorAll(this.contentName);
153        const last = items[items.length - 1];
154        this.tweenContainer.prepend(last);
155        this.setLeft(-this.itemWidth);
156    }
157
158    dragComplete(duration) {
159        this.isAnimating = true;
160        const currentLeft = this.getLeft();
161        if (this.infiniteMode) {
162            const count = Math.round(Math.abs(currentLeft) / this.itemWidth);
163            const targetLeft = -(count * this.itemWidth);
164            this.animateTo(targetLeft, duration, function () {
165                for (var i = 0; i < count; i++) {
166                    this._shiftFirst();
167                }
168                this.setLeft(0);
169                this.isAnimating = false;
170                this.controlSlide(true);
171            }.bind(this));
172        } else {
173            const maxLeft = this.getMaxLeft();
174            const minLeft = this.getMinLeft();
175            const totalItems = this._getTotalItems();
176            let currentIndex = Math.round(Math.abs(currentLeft) / this.itemWidth);
177            currentIndex = Math.max(0, Math.min(currentIndex, totalItems - 1));
178            const offsetFromCurrent = currentLeft + (currentIndex * this.itemWidth);
179            const dragRatio = Math.abs(offsetFromCurrent) / this.itemWidth;
180            let targetIndex = currentIndex;
181            if (offsetFromCurrent < 0 && dragRatio > 0.1 && currentIndex < totalItems - 1) {
182                targetIndex = currentIndex + 1;
183            } else if (offsetFromCurrent > 0 && dragRatio > 0.1 && currentIndex > 0) {
184                targetIndex = currentIndex - 1;
185            }
186            let targetLeft = -targetIndex * this.itemWidth;
187            targetLeft = Math.max(minLeft, Math.min(maxLeft, targetLeft));
188            this.animateTo(targetLeft, duration, function () {
189                this.isAnimating = false;
190                this.controlSlide(true);
191            }.bind(this));
192        }
193    }
194
195    _getTotalItems() {
196        return this.tweenContainer.querySelectorAll(this.contentName).length;
197    }
198
199    _swipeToNext(distance) {
200        if (this.isDragging || this.isAnimating) return;
201        this.isAnimating = true;
202        this.controlSlide(false);
203
204        if (this.infiniteMode) {
205            if (distance > 0) {
206                this._shiftLast();
207                this.setLeft(-this.itemWidth);
208                this.animateTo(0, this.animationDuration, function () {
209                    this.isAnimating = false;
210                    this.controlSlide(true);
211                }.bind(this));
212            } else {
213                this.animateTo(-this.itemWidth, this.animationDuration, function () {
214                    this._shiftFirst();
215                    this.setLeft(0);
216                    this.isAnimating = false;
217                    this.controlSlide(true);
218                }.bind(this));
219            }
220        } else {
221            const currentLeft = this.getLeft();
222            const totalItems = this._getTotalItems();
223            const currentIndex = Math.round(Math.abs(currentLeft) / this.itemWidth);
224            if (distance > 0 && currentIndex > 0) {
225                const targetLeft = -(currentIndex - 1) * this.itemWidth;
226                this.animateTo(targetLeft, this.animationDuration, function () {
227                    this.isAnimating = false;
228                    this.controlSlide(true);
229                }.bind(this));
230            } else if (distance < 0 && currentIndex < totalItems - this.totalDisplay) {
231                const targetLeft = -(currentIndex + 1) * this.itemWidth;
232                this.animateTo(targetLeft, this.animationDuration, function () {
233                    this.isAnimating = false;
234                    this.controlSlide(true);
235                }.bind(this));
236            } else {
237                this.isAnimating = false;
238                this.controlSlide(true);
239            }
240        }
241    }
242
243    _bindEvents() {
244        this.tweenContainer.addEventListener('mouseenter', function () {
245            this.isArea = true;
246            this.controlSlide(false);
247        }.bind(this));
248
249        this.tweenContainer.addEventListener('mouseleave', function () {
250            this.isArea = false;
251            this.controlSlide(true);
252        }.bind(this));
253
254        this.tweenContainer.addEventListener('mousedown', function (e) {
255            e.preventDefault();
256            this.isDragging = true;
257            this.lastClientX = e.clientX;
258            this.tweenContainer.style.cursor = !this.swipeMode ? 'grabbing' : 'pointer';
259            this.controlSlide(false);
260        }.bind(this));
261
262        this.tweenContainer.addEventListener('touchstart', function (e) {
263            this.isDragging = true;
264            this.lastClientX = e.touches[0].pageX;
265            this.tweenContainer.style.cursor = !this.swipeMode ? 'grabbing' : 'pointer';
266            this.controlSlide(false);
267        }.bind(this), { passive: true });
268
269        if (!this.swipeMode) {
270            const onDragMove = function (e) {
271                if (!this.isDragging || !(this._getTotalItems() > this.totalDisplay)) return;
272                e.preventDefault();
273                const clientX = e.clientX !== undefined ? e.clientX : e.touches[0].pageX;
274                const diff = clientX - this.lastClientX;
275                var newLeft = this.getLeft() + diff;
276                if (this.infiniteMode) {
277                    this.setLeft(newLeft);
278                    if (newLeft > 0) {
279                        this._shiftLast();
280                        this.setLeft(newLeft - this.itemWidth);
281                    } else if (newLeft < -this.itemWidth) {
282                        this._shiftFirst();
283                        this.setLeft(newLeft + this.itemWidth);
284                    }
285                } else {
286                    newLeft = this.applyRubberBand(newLeft);
287                    this.setLeft(newLeft);
288                }
289                this.lastClientX = clientX;
290                this.tweenContainer.querySelectorAll(this.contentName)
291                    .forEach(function (el) { el.style.pointerEvents = 'none'; });
292            }.bind(this);
293            const onDragEnd = function (e) {
294                if (!this.isDragging) return;
295                this.isDragging = false;
296                this.tweenContainer.style.cursor = 'grab';
297                this.dragComplete(100);
298                this.controlSlide(true);
299            }.bind(this);
300            document.addEventListener('mousemove', onDragMove);
301            this.tweenContainer.addEventListener('touchmove', onDragMove, { passive: false });
302            document.addEventListener('mouseup', onDragEnd);
303            document.addEventListener('touchend', onDragEnd);
304        } else {
305            const onSwipeMove = function (e) {
306                if (!this.isDragging) return;
307                e.preventDefault();
308                this.tweenContainer.querySelectorAll(this.contentName)
309                    .forEach(function (el) { el.style.pointerEvents = 'none'; });
310            }.bind(this);
311            const onSwipeEnd = function (e) {
312                if (!this.isDragging) return;
313                this.isDragging = false;
314                const clientX = e.clientX !== undefined ? e.clientX : e.changedTouches[0].clientX;
315                const distance = clientX - this.lastClientX;
316                if (Math.abs(distance) > 30) {
317                    this._swipeToNext(distance);
318                } else {
319                    this.controlSlide(true);
320                }
321                this.tweenContainer.style.cursor = 'pointer';
322            }.bind(this);
323            this.tweenContainer.addEventListener('mousemove', onSwipeMove);
324            this.tweenContainer.addEventListener('touchmove', onSwipeMove, { passive: false });
325            this.tweenContainer.addEventListener('mouseup', onSwipeEnd);
326            this.tweenContainer.addEventListener('touchend', onSwipeEnd);
327        }
328
329        if (this.leftBtn) {
330            this.leftBtn.addEventListener('click', function () {
331                this._swipeToNext(10);
332            }.bind(this));
333        }
334
335        if (this.rightBtn) {
336            this.rightBtn.addEventListener('click', function () {
337                this._swipeToNext(-10);
338            }.bind(this));
339        }
340    }
341
342    destroy() {
343        clearInterval(this.slideTimeout);
344    }
345}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.