PageSourceSearch

https://przewozimy.pl/wp-content/plugins/lexend-core/include/animejs/js/animejs-helper.js?ver=1.0.0

js przewozimy.pl collected 2026-09-24 14:27:21 UTC 18,483 bytes, 532 lines download raw bytes

1const $ = typeof jQuery !== 'undefined' ? jQuery : null;
2const { typesTesters, typesParsers } = dataAttrHelpers;
3
4const parseDataAttr = (dataAttr, types) => {
5    const options = {};
6    for (const row of dataAttr.split(';')) {
7        const match = row.trim().match(/^(.*?):([\s\S]*)$/);
8        if (!match) continue;
9        let [key, value] = [match[1], match[2]].map(a => a.trim());
10        if (aliases[key]) {
11            key = aliases[key];
12        }
13        for (const type in types) {
14            if (types[type].includes(key) && typesTesters[type](value)) {
15                value = typesParsers[type](value);
16                break;
17            }
18        }
19        if (typeof value === 'string') {
20            if (/^(\[|\{|anime\.|"|')/.test(value)) {
21                value = new Function(`return (${value})`)();
22            }
23        }
24        const parts = key.split('-');
25        let opts = options;
26        parts.forEach((part, i) => {
27            if (i < parts.length - 1) {
28                opts[part] = opts[part] || {};
29                opts = opts[part];
30            } else {
31                opts[part] = value;
32            }
33        });
34    }
35    return options;
36};
37
38const dataAnimeAttrType = {
39    string: [
40        "targets",
41        "onscroll",
42        "onscroll-target",
43    ],
44    number: [
45        "onview",
46    ],
47    boolean: [
48        "loop",
49        "onclick",
50        "onview",
51        "autoplay",
52        "onscroll",
53        "onscroll-target",
54        "onscroll-pen",
55    ]
56};
57
58const aliases = {
59    'onscroll': 'onscroll-target',
60    'onscroll-trigger': 'onscroll-triggerHook',
61};
62
63const runInstance = (el, instance, direction = 'restart') => {
64    if (direction === 'alternate') {
65        if (!el.animeToggleOpen) {
66            if (instance.reversed) {
67                instance.reverse();
68            }
69        } else {
70            if (!instance.reversed) {
71                instance.reverse();
72            }
73        }
74        el.animeToggleOpen = !el.animeToggleOpen;
75        instance.play();
76    } else if (direction === 'restart') {
77        instance.restart();
78    } else if (direction === 'reset') {
79        instance.reset();
80    } else {
81        throw 'invalid direction';
82    }
83};
84
85const loadingPromise = new Promise(r => {
86    document.addEventListener('DOMContentLoaded', e => {
87        setTimeout(() => {
88            r(true);
89        }, 1000 + 300);
90    });
91});
92
93const runHelper = async (el, options, instance) => {
94    const run = (direction = 'restart') => {
95        runInstance(el, instance, direction);
96    };
97    let autoRun = options.autoplay !== false;
98    if (options.onclick) {
99        const toggle = options.onclick === 'alternate';
100        el.addEventListener('click', e => {
101            e.preventDefault();
102            run(toggle ? 'alternate' : 'restart');
103        });
104        autoRun = false;
105    }
106    if (options.onscroll) {
107        const scrollMagicOptions = typeof options.onscroll === 'boolean' ? { triggerElement: el } : options.onscroll;
108        if (scrollMagicOptions.target) {
109            scrollMagicOptions.triggerElement = scrollMagicOptions.target;
110            delete scrollMagicOptions.target;
111        }
112        const controller = new ScrollMagic.Controller({
113            ...(scrollMagicOptions.controller || {}),
114        });
115        const penOption = scrollMagicOptions.pen;
116        delete scrollMagicOptions.controller;
117        delete scrollMagicOptions.pen;
118        const sceneOptions = scrollMagicOptions || {};
119        const triggerElement = sceneOptions.triggerElement ? (
120            typeof sceneOptions.triggerElement === 'string'
121                ? document.querySelector(sceneOptions.triggerElement)
122                : sceneOptions.triggerElement
123        ) : el;
124        delete sceneOptions.triggerElement;
125        const scene = new ScrollMagic.Scene({
126            triggerElement,
127            duration: '100%',
128            triggerHook: 1,
129            ...sceneOptions,
130        });
131        if (penOption) {
132            const pen = penOption === true ? triggerElement : document.querySelector(penOption);
133            scene.setPin(pen);
134        }
135        scene.on('progress', e => {
136            instance.seek(e.progress * instance.duration);
137        }).addTo(controller);
138
139        // Store the ScrollMagic scene and controller
140        el.animeScrollMagicScene = scene;
141        el.animeScrollMagicController = controller;
142
143        delete options.onscroll;
144        autoRun = false;
145    }
146    if (options.onhover) {
147        $(el).on('mouseenter mouseleave', () => {
148            run('alternate');
149        });
150        autoRun = false;
151    }
152    await loadingPromise;
153    if (typeof options.onview !== 'undefined' && options.onview !== false) {
154        const offset = typeof options.onview === 'number' ? options.onview : 0;
155        const handler = () => {
156            if (window.innerHeight > el.getBoundingClientRect().top - offset) {
157                window.removeEventListener('scroll', handler);
158                window.removeEventListener('resize', handler);
159                run();
160            }
161        };
162        window.addEventListener('scroll', handler);
163        window.addEventListener('resize', handler);
164        handler();
165        autoRun = false;
166    }
167    if (options.media) {
168        const mediaArray = typeof options.media === 'string' ? [options.media] : options.media;
169        const mediaList = [];
170        for (let i = 0; i < mediaArray.length; i++) {
171            const bp = mediaArray[i];
172            const group = i % 2 === 0 ? (mediaList[i / 2] = []) : mediaList[(i - 1) / 2];
173            group.push({ bp, type: i % 2 === 0 ? 'min' : 'max' });
174        }
175        const mediaText = mediaList.map(mediaArray => '(' + mediaArray.map(({ bp, type }) => {
176            const bpSize = breakpoints[bp] || 0;
177            return `(${type}-width: ${type === 'max' ? bpSize - 1 : bpSize}px)`;
178        }).join(' and ') + ')').join(' or ');
179        const media = matchMedia(mediaText);
180        const update = () => {
181            run(media.matches ? "restart" : "reset");
182        };
183        media.onchange = update;
184        update();
185        autoRun = false;
186    }
187    if (autoRun) {
188        run();
189    } else if (options.animejs_animation_type === 'disable') {
190        removeAnimationStyles($(el));
191        destroyScrollMagicInstance($(el));
192    }
193};
194
195const runDataAnime = async (el) => {
196    if (!AnimeJSHelper.isDeviceAllowed(el)) {
197        return; // Exit if the animation is not allowed on this device
198    }
199    const options = parseDataAttr(el.getAttribute('data-anime') || '', dataAnimeAttrType);
200    const targets = options.targets ? [...$(options.targets, el)] : el;
201    Object.assign(options, { targets });
202    let instance;
203    if (options.timeline) {
204        const timelineName = options.timeline;
205        delete options.timeline;
206        if (!timelines[timelineName]) {
207            if (!timelinesPromises[timelineName]) {
208                timelinesPromises[timelineName] = new Promise(resolve => {
209                    timelinesResolvers[timelineName] = resolve;
210                });
211            }
212            await timelinesPromises[timelineName];
213        }
214        instance = timelines[timelineName](el, options);
215    } else {
216        instance = anime(options);
217    }
218    instance.pause();
219
220    el.animeInstance = instance;
221    runHelper(el, options, instance);
222};
223
224const timelines = {};
225const timelinesPromises = {};
226const timelinesResolvers = {};
227
228const defineAnimeTimelineHelper = (name, fn) =>  {
229    timelines[name] = fn;
230    if (timelinesResolvers[name]) {
231        timelinesResolvers[name](fn);
232    }
233};
234
235Object.assign(window, { defineAnimeTimelineHelper });
236
237const runDataAnimeToggle = async (el) => {
238    const toggleSelector = el.getAttribute('data-anime-toggle') || '';
239    el.addEventListener('click', e => {
240        e.preventDefault();
241        const els = [...$(toggleSelector)];
242        els.forEach(other => {
243            const instance = other.animeTimelineInstance || other.animeInstance;
244            if (!instance) return;
245            runInstance(other, instance, 'alternate');
246        });
247    });
248};
249
250// Stop and reset the animation
251const resetAnimation = function($element) {
252    const instance = $element[0].animeInstance;
253    if (instance) {
254        instance.pause();
255        instance.reset();
256        instance.remove();
257        anime.remove($element[0]);
258    }
259};
260            
261// Remove inline styles
262const removeAnimationStyles = function($element) {
263    $element.css({
264        opacity: '',
265        transform: ''
266    });
267};
268
269// Stop and destroy ScrollMagic scene and controller
270const destroyScrollMagicInstance = function($element) {
271    const scrollMagicScene = $element[0].animeScrollMagicScene;
272    const scrollMagicController = $element[0].animeScrollMagicController;
273    if (scrollMagicScene && scrollMagicController) {
274        scrollMagicScene.off('progress');
275        scrollMagicScene.remove();
276        scrollMagicController.destroy(true);
277        $element[0].animeScrollMagicScene = null;
278        $element[0].animeScrollMagicController = null;
279    }
280};
281
282const getCurrentDevice = () => {
283    const width = window.innerWidth;
284    if (width < 767) {
285        return 'mobile';
286    } else if (width < 1023) {
287        return 'tablet';
288    } else {
289        return 'desktop';
290    }
291};
292
293const isDeviceAllowed = (el) => {
294    const allowedDevices = el.getAttribute('data-anime-devices');
295    if (!allowedDevices) return true; // If no devices specified, allow all
296
297    const deviceList = allowedDevices.split(',');
298    const currentDevice = getCurrentDevice();
299    return deviceList.includes(currentDevice);
300};
301
302const AnimeJSHelper = {
303    currentDevice: null,
304
305    init: function() {
306        this.currentDevice = getCurrentDevice();
307        
308        if (window.elementorFrontend && elementorFrontend.isEditMode()) {
309            elementor.channels.editor.on('change', this.onElementorChange);
310        } else {
311            this.applyAnimations();
312        }
313        
314        // Add resize event listener with debounce
315        let resizeTimer;
316        window.addEventListener('resize', () => {
317            clearTimeout(resizeTimer);
318            resizeTimer = setTimeout(() => this.handleResize(), 250);
319        });
320    },
321
322    handleResize: function() {
323        const newDevice = getCurrentDevice();
324        if (newDevice !== this.currentDevice) {
325            this.currentDevice = newDevice;
326            this.applyAnimations();
327        }
328    },
329
330    updateElementAnimation: function(el) {
331        const allowedDevices = el.getAttribute('data-anime-devices');
332        
333        if (allowedDevices) {
334            const deviceList = allowedDevices.split(',');
335            if (deviceList.includes(this.currentDevice)) {
336                this.enableAnimation(el);
337            } else {
338                this.disableAnimation(el);
339            }
340        } else {
341            // If no devices are specified, run the animation on all devices
342            this.enableAnimation(el);
343        }
344    },
345
346    isDeviceAllowed: function(el) {
347        const allowedDevices = el.getAttribute('data-anime-devices');
348        if (!allowedDevices) return true; // If no devices specified, allow all
349    
350        const deviceList = allowedDevices.split(',');
351        return deviceList.includes(this.currentDevice);
352    },
353
354    enableAnimation: function(el) {
355        // Remove any existing instance
356        if (el.animeInstance) {
357            el.animeInstance.pause();
358            el.animeInstance.reset();
359            anime.remove(el);
360        }
361        // Remove any existing ScrollMagic scene and controller
362        if (el.animeScrollMagicScene) {
363            el.animeScrollMagicScene.destroy(true);
364            el.animeScrollMagicScene = null;
365        }
366        if (el.animeScrollMagicController) {
367            el.animeScrollMagicController.destroy(true);
368            el.animeScrollMagicController = null;
369        }
370        // Run the animation
371        runDataAnime(el);
372    },
373
374    disableAnimation: function(el) {
375        if (el.animeInstance) {
376            el.animeInstance.pause();
377            el.animeInstance.reset();
378            anime.remove(el);
379            el.animeInstance = null;
380        }
381        removeAnimationStyles($(el));
382        if (el.animeScrollMagicScene) {
383            el.animeScrollMagicScene.destroy(true);
384            el.animeScrollMagicScene = null;
385        }
386        if (el.animeScrollMagicController) {
387            el.animeScrollMagicController.destroy(true);
388            el.animeScrollMagicController = null;
389        }
390    },
391
392    applyAnimations: function() {
393        $('[data-anime]').each((index, el) => {
394            this.updateElementAnimation(el);
395        });
396    },
397
398    applyAnimation: async function($element) {
399        if ($element.length === 0) {
400            console.warn('No element found to apply animation');
401            return;
402        }
403        const el = $element[0];
404        await runDataAnime(el);
405    },
406
407    onElementorChange: function(controlView, elementView) {
408        const changed = controlView.model.get('name');
409        if (changed.indexOf('animejs_') === 0) {
410            const $element = elementView.$el;
411            AnimeJSHelper.updateAnimation($element, elementView);
412        }
413    },
414
415    updateAnimation: function($element, elementView, isInitial = false) {
416        const settings = elementView.getEditModel().get('settings').toJSON();
417        
418        if (settings.animejs_animation_type !== 'disable') {
419            if (settings.animejs_animation_type || !isInitial) {
420                const dataAnime = AnimeJSHelper.generateDataAnime(settings);
421                
422                $element.attr('data-anime', dataAnime);
423                $element.addClass('animejs-element');
424    
425                // Add selected devices as a data attribute
426                if (settings.animejs_devices && settings.animejs_devices.length > 0) {
427                    $element.attr('data-anime-devices', settings.animejs_devices.join(','));
428                } else {
429                    $element.removeAttr('data-anime-devices');
430                }
431    
432                // Check if the current device is allowed before applying the animation
433                if (this.isDeviceAllowed($element[0])) {
434                    // Re-apply animation
435                    this.enableAnimation($element[0]);
436                } else {
437                    // Disable animation if the current device is not allowed
438                    this.disableAnimation($element[0]);
439                }
440            }
441        } else {
442            // Remove data-anime attribute and classes
443            $element.removeAttr('data-anime');
444            $element.removeAttr('data-anime-devices');
445            $element.removeClass('animejs-element');
446    
447            this.disableAnimation($element[0]);
448        }
449    
450        if (settings.animejs_animation_type !== 'onscroll') {
451            destroyScrollMagicInstance($element);
452        }
453    },
454    
455    generateDataAnime: function(settings) {
456        let dataAnime = [];
457
458        if (settings.animejs_onscroll_viewport === 'top') {
459            settings.animejs_onscroll_viewport = 0;
460        } else if (settings.animejs_onscroll_viewport === 'center') {
461            settings.animejs_onscroll_viewport = 0.5;
462        } else {
463            settings.animejs_onscroll_viewport = 1;
464        }
465
466        if (settings.animejs_animation_type === 'onview') {
467            dataAnime.push(`onview: ${settings.animejs_onview_trigger_viewport}`);
468            if (settings.animejs_onview_repeat === 'yes') {
469                dataAnime.push(`loop: true`);
470            } else {
471                dataAnime.push(`loop: false`);
472            }
473            if (settings.animejs_onview_direction === 'alternate') {
474                dataAnime.push(`direction: alternate`);
475            } else if (settings.animejs_onview_direction === 'reverse') {
476                dataAnime.push(`direction: reverse`);
477            }
478        } else if (settings.animejs_animation_type === 'onscroll') {
479            dataAnime.push(`onscroll: ${settings.animejs_onscroll_scene || 'true'}`);
480            dataAnime.push(`onscroll-trigger: ${settings.animejs_onscroll_viewport}`);
481            dataAnime.push(`onscroll-duration: ${settings.animejs_onscroll_duration.size}%`);
482            dataAnime.push(`onscroll-offset: ${settings.animejs_onscroll_offset}`);
483        }
484
485        if (settings.animejs_animation_type !== 'disable') {
486
487            const properties = ['opacity', 'translateX', 'translateY', 'scale', 'rotate', 'skew'];
488            properties.forEach(prop => {
489                const from = settings[`animejs_animation_from_${prop}`];
490                const to = settings[`animejs_animation_to_${prop}`];
491                if (from !== '' && to !== '') {
492                    dataAnime.push(`${prop}: [${from}, ${to}]`);
493                } else if (from !== '') {
494                    dataAnime.push(`${prop}: ${from}`);
495                } else if (to !== '') {
496                    dataAnime.push(`${prop}: ${to}`);
497                }
498            });
499
500            let easing = settings.animejs_animation_easing;
501            if (easing === 'custom') {
502                easing = settings.animejs_animation_easing_custom;
503            }
504            dataAnime.push(`easing: '${easing}'`);
505            dataAnime.push(`duration: ${settings.animejs_animation_speed}`);
506            dataAnime.push(`delay: ${settings.animejs_animation_delay}`);
507
508            if (settings.animejs_onview_targets && settings.animejs_onview_staggering) {
509                let stagger = `anime.stagger(${settings.animejs_onview_staggering}`;
510                if (settings.animejs_onview_staggering_start_after) {
511                    stagger += `, {start: ${settings.animejs_onview_staggering_start_after}`;
512                    if (settings.animejs_onview_staggering_from && settings.animejs_onview_staggering_from !== 'first') {
513                        stagger += `, from: '${settings.animejs_onview_staggering_from}'`;
514                    }
515                    stagger += `}`;
516                }
517                stagger += `)`;
518                dataAnime.push(`delay: ${stagger}`);
519            }
520            
521        }
522
523        return dataAnime.join('; ');
524    }
525};
526
527// Initialize AnimeJSHelper
528$(document).ready(AnimeJSHelper.init.bind(AnimeJSHelper));
529
530// Keep the existing event listeners and function calls
531dataAttrHelpers.watchDataAttr('data-anime', runDataAnime);
532dataAttrHelpers.watchDataAttr('data-anime-toggle', runDataAnimeToggle);

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.