PageSourceSearch

https://conteudo.espanholdeverdade.com.br/wp-content/plugins/pixel…/dist/scripts/public.js?ver=12.5.4.1

js espanholdeverdade.com.br collected 2026-10-05 20:48:46 UTC 370,493 bytes, 8,222 lines download raw bytes

1/* global pysOptions */
2
3! function ($, options) {
4    if (options.debug) {
5        console.log('PYS:', options);
6    }
7
8    var uniqueId = {};
9
10    // State tracking for AND trigger logic: { eventId: { triggered: {}, total: N, fired: false } }
11    var pysCustomEventsState = {};
12
13    // State tracking for "once per page" fire frequency: { eventId: true }
14    var pysEventFiredOnce = {};
15    if (options.triggerLogic) {
16        Object.entries(options.triggerLogic).forEach(function([eventId, logic]) {
17            if (logic === 'AND') {
18                var count = 0;
19                Object.values(options.triggerEventTypes).forEach(function(events) {
20                    if (events.hasOwnProperty(eventId)) count++;
21                });
22                pysCustomEventsState[eventId] = { triggered: {}, total: count, fired: false };
23            }
24        });
25    }
26
27    var firstVisit = false;
28
29    var isTrackEventForGA = [];
30
31    var isAdsLoad = false;
32
33    let gtm_variables = {};
34    let gtm_datalayername = "dynamicVariable";
35    var domain = '';
36    if(options.hasOwnProperty("track_cookie_for_subdomains") && options.track_cookie_for_subdomains) {
37        domain = getRootDomain(true);
38    }
39
40    /**
41     * Resolve parameter value based on mode (static or dynamic)
42     *
43     * @param {Object|string} param - Parameter object with { value, selector } or string value
44     * @returns {string|null} - Resolved value
45     */
46    function resolveParamValue(param, key = '') {
47
48        // 1️⃣ null / undefined - skip this parameter
49        if (param === null || param === undefined) {
50            return null;
51        }
52
53        // 2️⃣ primitive
54        if (typeof param !== 'object') {
55            return param;
56        }
57
58        // 3️⃣ array
59        if (Array.isArray(param)) {
60            return param.map(item => resolveParamValue(item, key));
61        }
62
63        // 4️⃣ NEW FORMAT OBJECT (config-object)
64        const isConfigObject =
65            ('value' in param || 'selector' in param || 'dynamic' in param || 'input_type' in param) &&
66            Object.keys(param).every(k =>
67                ['value','selector','dynamic','input_type','name'].includes(k)
68            );
69
70        if (isConfigObject) {
71
72            // STATIC MODE
73            const isStatic =
74                !param.dynamic ||
75                !param.selector ||
76                param.selector.trim() === '';
77
78            if (isStatic) {
79                let value = param.value ?? null;
80
81                if (param.input_type === "float" || param.input_type === "int") {
82                    value = extractNumericValue(
83                        value,
84                        param.input_type === "int"
85                    );
86                }
87
88                return value;
89            }
90
91            // DYNAMIC MODE
92            try {
93                const el = document.querySelector(param.selector);
94                if (!el) return null;
95
96                let value =
97                    el.value ??
98                    el.innerText ??
99                    el.textContent ??
100                    el.getAttribute("content") ??
101                    el.getAttribute("data-value") ??
102                    null;
103
104                if (param.input_type === "float" || param.input_type === "int") {
105                    value = extractNumericValue(
106                        value,
107                        param.input_type === "int"
108                    );
109                }
110
111                return value;
112
113            } catch {
114                return null;
115            }
116        }
117
118        // 5️⃣ Plain object (recursive traversal) - filter out null/undefined values
119        return Object.fromEntries(
120            Object.entries(param)
121                .map(([k, v]) => [k, resolveParamValue(v, k)])
122                .filter(([k, v]) => v !== null && v !== undefined)
123        );
124    }
125
126    function extractNumericValue(value, isInt=false) {
127        if (value === null || value === undefined) {
128            return null;
129        }
130        if (isInt) {
131            return parseInt(value);
132        }
133        return parseFloat(value);
134    }
135
136    var loadTags = [];
137
138    var dummyPinterest = function () {
139
140        /**
141         * Public API
142         */
143        return {
144            tag: function() {
145                return "pinterest";
146            },
147            isEnabled: function () {},
148
149            disable: function () {},
150
151            loadPixel: function () {},
152
153            fireEvent: function (name, data) {
154                return false;
155            },
156
157            onAdSenseEvent: function (event) {},
158
159            onClickEvent: function (params) {},
160
161            onWatchVideo: function (params) {},
162
163            onCommentEvent: function (event) {},
164
165            onFormEvent: function (params) {},
166
167            onDownloadEvent: function (params) {},
168
169
170
171            onWooAddToCartOnButtonEvent: function (product_id) {},
172
173            onWooAddToCartOnSingleEvent: function (product_id, qty, product_type, is_external, $form) {},
174
175            onWooRemoveFromCartEvent: function (cart_item_hash) {},
176
177            onWooAffiliateEvent: function (product_id) {},
178
179            onWooPayPalEvent: function (event) {},
180
181            onEddAddToCartOnButtonEvent: function (download_id, price_index, qty) {},
182
183            onEddRemoveFromCartEvent: function (item) {},
184
185            onPageScroll: function (event) {},
186            onTime: function (event) {
187
188            },
189
190        }
191
192    }();
193
194    var dummyBing = function () {
195
196        /**
197         * Public API
198         */
199        return {
200            tag: function() {
201                return "bing";
202            },
203            isEnabled: function () {},
204
205            disable: function () {},
206
207            loadPixel: function () {},
208
209            fireEvent: function (name, data) {
210                return false;
211            },
212
213            onAdSenseEvent: function (event) {},
214
215            onClickEvent: function (params) {},
216
217            onWatchVideo: function (params) {},
218
219            onCommentEvent: function (event) {},
220
221            onFormEvent: function (params) {},
222
223            onDownloadEvent: function (params) {},
224
225
226            onWooAddToCartOnButtonEvent: function (product_id) {},
227
228            onWooAddToCartOnSingleEvent: function (product_id, qty, product_type, is_external, $form) {},
229
230            onWooRemoveFromCartEvent: function (cart_item_hash) {},
231
232            onWooAffiliateEvent: function (product_id) {},
233
234            onWooPayPalEvent: function (event) {},
235
236            onEddAddToCartOnButtonEvent: function (download_id, price_index, qty) {},
237
238            onEddRemoveFromCartEvent: function (item) {},
239            onPageScroll: function (event) {},
240            onTime: function (event) {
241
242            },
243        }
244
245    }();
246
247	var dummyReddit = function () {
248		/**
249		 * Public API
250		 */
251		return {
252			tag: function () {
253				return "reddit";
254			},
255			isEnabled: function () {
256			},
257
258			disable: function () {
259			},
260
261			loadPixel: function () {
262			},
263
264			fireEvent: function ( name, data ) {
265				return false;
266			},
267
268			onAdSenseEvent: function ( event ) {
269			},
270
271			onClickEvent: function ( params ) {
272			},
273
274			onWatchVideo: function ( params ) {
275			},
276
277			onCommentEvent: function ( event ) {
278			},
279
280			onFormEvent: function ( params ) {
281			},
282
283			onDownloadEvent: function ( params ) {
284			},
285
286			onWooAddToCartOnButtonEvent: function ( product_id ) {
287			},
288
289			onWooAddToCartOnSingleEvent: function ( product_id, qty, product_type, is_external, $form ) {
290			},
291
292			onWooRemoveFromCartEvent: function ( cart_item_hash ) {
293			},
294
295			onWooAffiliateEvent: function ( product_id ) {
296			},
297
298			onWooPayPalEvent: function ( event ) {
299			},
300
301			onEddAddToCartOnButtonEvent: function ( download_id, price_index, qty ) {
302			},
303
304			onEddRemoveFromCartEvent: function ( item ) {
305			},
306
307			onPageScroll: function ( event ) {
308			},
309
310			onTime: function ( event ) {
311			},
312		}
313	}();
314
315    var Utils = function (options) {
316
317
318        var Pinterest = dummyPinterest;
319
320        var Bing = dummyBing;
321
322	    var Reddit = dummyReddit;
323
324        var gtag_loaded = false;
325
326        var gtm_loaded = false;
327
328        let isNewSession = checkSession();
329
330        let dataLayerName = 'dataLayerPYS';
331
332        let GTMdataLayerName = 'dataLayer';
333
334
335        function loadPixels() {
336
337            if (!options.gdpr.all_disabled_by_api) {
338                if (!options.gdpr.tiktok_disabled_by_api) {
339                    TikTok.loadPixel();
340                }
341
342                if (!options.gdpr.facebook_disabled_by_api) {
343                    Facebook.loadPixel();
344                }
345
346                if (!options.gdpr.analytics_disabled_by_api) {
347                    Analytics.loadPixel();
348                }
349
350                if (!options.gdpr.google_ads_disabled_by_api) {
351                    GAds.loadPixel();
352                }
353
354                if (!options.gdpr.analytics_disabled_by_api) {
355                    GTM.loadPixel();
356                }
357
358                if (!options.gdpr.pinterest_disabled_by_api) {
359                    Pinterest.loadPixel();
360                }
361
362                if (!options.gdpr.bing_disabled_by_api) {
363                    Bing.loadPixel();
364                }
365
366	            if (!options.gdpr.reddit_disabled_by_api) {
367		            Reddit.loadPixel();
368	            }
369
370            }
371            if (options.gdpr.consent_magic_integration_enabled && typeof CS_Data !== "undefined") {
372                if (typeof CS_Data.cs_google_analytics_consent_mode !== "undefined" && CS_Data.cs_google_analytics_consent_mode == 1) {
373                    Analytics.loadPixel();
374                }
375                if (typeof CS_Data.cs_google_ads_consent_mode !== "undefined" && CS_Data.cs_google_ads_consent_mode == 1 ) {
376                    GAds.loadPixel();
377                }
378            }
379        }
380
381        /**
382         * WATCHVIDEO UTILS
383         */
384
385        function isJSApiAttrEnabled(url) {
386            return url.indexOf('enablejsapi') > -1;
387        }
388
389        function isOriginAttrEnabled(url) {
390            return url.indexOf('origin') > -1;
391        }
392
393        // Returns key/value pairs of percentages: number of seconds to achieve
394        function getVideoCompletionMarks(duration) {
395
396            var marks = {};
397            var points = [0, 10, 50, 90, 100];
398
399            for (var i = 0; i < points.length; i++) {
400
401                var _point = points[i];
402                var _mark = _point + '%';
403                var _time = duration * _point / 100;
404
405                if (_point === 100) {
406                    _time = _time - 1;
407                }
408
409                // 10% => 123
410                marks[_mark] = Math.floor(_time);
411
412            }
413
414            return marks;
415
416        }
417
418        // Determine if the element is a YouTube video or not
419        function tagIsYouTubeVideo(tag) {
420            var src = tag.src || '';
421            return src.indexOf('youtube.com/embed/') > -1 || src.indexOf('youtube.com/v/') > -1;
422        }
423
424        function tagIsYouTubeAsyncVideo(tag) {
425            if(tag.src && tag.src.indexOf("data:image") !== -1) return false; // video is loaded
426            var keys = Object.keys(tag.dataset);
427            for(var i = 0;i<keys.length;i++) {
428                if(keys[i].toLowerCase().indexOf("src") > -1) {
429                    var src = tag.dataset[keys[i]];
430                    return src.indexOf('youtube.com/embed/') > -1 || src.indexOf('youtube.com/v/') > -1;
431                }
432            }
433            return false; //not find src
434        }
435
436        // Turn embed objects into iframe objects and ensure they have the right parameters
437        function normalizeYouTubeIframe(tag) {
438
439            var loc = window.location;
440            var a = document.createElement('a');
441            a.href = tag.src;
442            a.hostname = 'www.youtube.com';
443            a.protocol = loc.protocol;
444            var tmpPathname = a.pathname.charAt(0) === '/' ? a.pathname : '/' + a.pathname; // IE10 shim
445
446            if (!isJSApiAttrEnabled(a.search)) {
447                a.search = (a.search.length > 0 ? a.search + '&' : '') + 'enablejsapi=1';
448            }
449
450            // for security reasons, YouTube wants an origin parameter set that matches our hostname
451            if (!isOriginAttrEnabled(a.search) && loc.hostname.indexOf('localhost') === -1) {
452
453                var port = loc.port ? ':' + loc.port : '';
454                var origin = loc.protocol + '%2F%2F' + loc.hostname + port;
455
456                a.search = a.search + '&origin=' + origin;
457
458            }
459
460            if (tag.type === 'application/x-shockwave-flash') {
461
462                var newIframe = document.createElement('iframe');
463                newIframe.height = tag.height;
464                newIframe.width = tag.width;
465                tmpPathname = tmpPathname.replace('/v/', '/embed/');
466
467                tag.parentNode.parentNode.replaceChild(newIframe, tag.parentNode);
468
469                tag = newIframe;
470
471            }
472
473            a.pathname = tmpPathname;
474
475            if (tag.src !== a.href + a.hash) {
476                tag.src = a.href + a.hash;
477            }
478
479            return tag;
480
481        }
482
483        // Add event handlers for events emitted by the YouTube API
484        function addYouTubeEvents(iframe) {
485
486            var player = YT.get(iframe.id);
487            if (!player) {
488                player = new YT.Player(iframe, {});
489            }
490
491            if (typeof iframe.pauseFlag === 'undefined') {
492
493                iframe.pauseFlag = false;
494                player.addEventListener('onStateChange', function (evt) {
495                    onYouTubePlayerStateChange(evt, iframe);
496                });
497
498                player.addEventListener('onPlaybackRateChange', function(evt) {
499                    var currRate = evt.data;
500                    var prevRate = iframe._pysSpeedRate !== undefined ? iframe._pysSpeedRate : 1;
501                    iframe._pysSpeedRate = currRate;
502                    if(currRate == prevRate) return;
503                    if (options.triggerEventTypes && options.triggerEventTypes.video_speed) {
504                        var href = window.location.href;
505                        var ytVideoId = '';
506                        try { ytVideoId = player.getVideoData().video_id || ''; } catch(e) {}
507                        Object.keys(options.triggerEventTypes.video_speed).forEach(function(evtId) {
508                            var evtConfig   = options.triggerEventTypes.video_speed[evtId];
509                            var urls        = Array.isArray(evtConfig) ? evtConfig : (evtConfig.urls || []);
510                            var speedRate   = Array.isArray(evtConfig) ? 'any' : (evtConfig.speed_rate || 'any');
511                            var evtTriggers = Array.isArray(evtConfig) ? [] : (evtConfig.triggers || []);
512                            var pageOk      = !urls || urls.length === 0 || urls.some(function(u) { return u === '*' || u === '' || href.indexOf(u) !== -1; });
513                            var rateOk      = speedRate === 'any' ? currRate !== prevRate : (speedRate === 'increase' ? currRate > prevRate : currRate < prevRate);
514                            var videoOk     = evtTriggers.length === 0 || evtTriggers.some(function(t) { return t.type === 'youtube' && t.rule === ytVideoId; });
515                            if (pageOk && rateOk && videoOk) {
516                                Utils.handleTriggerFired(evtId, 'video_speed');
517                            }
518                        });
519                    }
520                    if (options.dynamicEvents && options.dynamicEvents.automatic_event_video_speed) {
521                        var ytSpeedUrl = iframe.src || '';
522                        var ytSpeedTitle = '';
523                        try { ytSpeedTitle = player.getVideoData().title || ''; } catch(e) {}
524                        var params = {
525                            video_url: ytSpeedUrl,
526                            video_type: 'youtube',
527                            video_title: ytSpeedTitle || 'Unknown Title',
528                            playback_speed: currRate,
529                            element: 'iframe'
530                        };
531                        Object.keys(options.dynamicEvents.automatic_event_video_speed).forEach(function(slug) {
532                            var pysEvent = Utils.clone(options.dynamicEvents.automatic_event_video_speed[slug]);
533                            Utils.copyProperties(params, pysEvent.params);
534                            var px = getPixelBySlag(slug); if (px) px.fireEvent(pysEvent.name, pysEvent);
535                        });
536                    }
537                });
538
539            }
540
541        }
542
543        function addDynYouTubeVideos(el) {
544            // We only bind to iFrames with a YouTube URL with the enablejsapi=1 and
545            // origin=<<hostname>> parameters
546            if (el.tagName === 'IFRAME'
547                && tagIsYouTubeVideo(el)
548                && isJSApiAttrEnabled(el.src)
549                && isOriginAttrEnabled(el.src))
550            {
551                addYouTubeEvents(el);
552            }
553        }
554
555        // Event handler for events emitted from the YouTube API
556        function onYouTubePlayerStateChange(evt, iframe) {
557
558            var stateIndex = evt.data;
559            var player = evt.target;
560            var targetVideoUrl = player.getVideoUrl();
561            var targetVideoId = targetVideoUrl.match(/[?&]v=([^&#]*)/)[1]; // Extract the ID
562            var playerState = player.getPlayerState();
563            var marks = getVideoCompletionMarks(player.getDuration());
564
565            iframe.playTracker = iframe.playTracker || {};
566
567            if (playerState === YT.PlayerState.PLAYING && !iframe.timer) {
568
569                clearInterval(iframe.timer);
570
571                // check every second to see if we've hit any of our percentage viewed marks
572                iframe.timer = setInterval(function () {
573                    checkYouTubeCompletion(player, marks, iframe.videoId);
574                }, 1000);
575
576            } else {
577
578                clearInterval(iframe.timer);
579                iframe.timer = false;
580
581            }
582
583            // playlist edge-case handler
584            if (stateIndex === YT.PlayerState.PLAYING) {
585                iframe.playTracker[targetVideoId] = true;
586                iframe.videoId = targetVideoId;
587                iframe.pauseFlag = false;
588            }
589
590            if (!iframe.playTracker[iframe.videoId]) {
591                return false; // this video hasn't started yet, so this is spam
592            }
593
594            if (stateIndex === YT.PlayerState.PAUSED) {
595
596                if (!iframe.pauseFlag) {
597                    iframe.pauseFlag = true;
598                } else {
599                    return false; // we don't want to fire consecutive pause events
600                }
601
602            }
603
604        }
605
606        // Trigger event if YouTube video mark was reached
607        function checkYouTubeCompletion(player, marks, videoId) {
608
609            var currentTime = player.getCurrentTime();
610
611            player[videoId] = player[videoId] || {};
612
613            for (var key in marks) {
614
615                if (marks[key] <= currentTime && !player[videoId][key]) {
616                    player[videoId][key] = true;
617
618                    var data = player.getVideoData();
619
620                    if (key === '0%') {
621                        key = 'play';
622                    }
623
624                    var params = {
625                        video_type: 'youtube',
626                        video_id: videoId,
627                        video_title: data.title,
628                    };
629
630                    let disable_watch_video = [];
631
632                    //Custom
633                    if ( options.triggerEventTypes.hasOwnProperty( "video_view" ) ) {
634                        Object.entries( options.triggerEventTypes.video_view ).forEach( function ( [ trigger_id, triggers ] ) {
635                            triggers.forEach( function ( trigger ) {
636                                if ( trigger.type === 'youtube' && trigger.rule === videoId ) {
637
638                                    let pixels = Object.keys( options.triggerEvents[ trigger_id ] );
639                                    for ( let i = 0; i < pixels.length; i++ ) {
640                                        let event = Utils.clone( options.triggerEvents[ trigger_id ][ pixels[ i ] ] );
641
642                                        if ( trigger.disable_watch_video ) {
643                                            disable_watch_video.push( pixels[ i ] );
644                                        }
645
646                                        if ( currentTime >= marks[ trigger.value ] ) {
647											if (pixels[i] !== 'reddit') {
648												event.params["progress"] = key;
649												Utils.copyProperties( params, event.params );
650											}
651
652                                            if ( event.fired !== true ) {
653                                                if ( Utils.isEventInTimeWindow( event.name, event, 'dyn_' + pixels[ i ] + '_' + trigger_id ) ) {
654                                                    event = Utils.getFormFilledData( event );
655                                                    getPixelBySlag( pixels[ i ] ).fireEvent( event.name, event );
656                                                    options.triggerEvents[ trigger_id ][ pixels[ i ] ].fired = true;
657                                                }
658                                            }
659                                        }
660                                    }
661                                }
662                            } )
663                        } )
664                    }
665
666                    // Auto
667                    if( options.automatic.enable_video
668                        && options.automatic.enable_youtube
669                        && options.dynamicEvents.hasOwnProperty("automatic_event_video")
670                    ) {
671                        var pixels = Object.keys(options.dynamicEvents.automatic_event_video);
672
673                        for (var i = 0; i < pixels.length; i++) {
674                            if ( disable_watch_video.includes( pixels[ i ] ) ) {
675                                continue;
676                            }
677                            var event = Utils.clone(options.dynamicEvents.automatic_event_video[pixels[i]]);
678
679							if ( pixels[ i ] !== 'reddit' ) {
680								event.params[ "progress" ] = key;
681								Utils.copyProperties(params, event.params)
682							}
683
684                            if ( pixels[i] === 'tiktok' || pixels[i] === 'reddit' ) {
685                                var time_trigger = event.automatic_event_video_trigger;
686                                if ( currentTime >= marks[time_trigger] && event.fired !== true ) {
687                                    getPixelBySlag(pixels[i]).onWatchVideo(event);
688
689                                    //tiktok and reddit watch video fire once
690                                    options.dynamicEvents.automatic_event_video[pixels[i]].fired = true;
691                                }
692                            } else {
693                                Utils.copyProperties(Utils.getRequestParam
693s(), event.params);
694                                getPixelBySlag(pixels[i]).onWatchVideo(event);
695                            }
696                        }
697                    }
698
699                    if(key == "play") {
700
701                        $.each(options.triggerEventTypes, function (triggerType, events) {
702                            $.each(events, function (eventId, triggers) {
703                                switch (triggerType) {
704                                    case 'video_play':
705                                        Utils.handleTriggerFired(eventId, triggerType);
706                                        break;
707                                }
708
709                            });
710                        });
711                    }
712
713                }
714
715            }
716
717        }
718
719        // Determine if the element is a Vimeo video or not
720        function tagIsVimeoVideo(tag) {
721            var src = tag.src || '';
722            return src.indexOf('player.vimeo.com/video/') > -1;
723        }
724
725        function tagIsAsincVimeoVideo(tag) {
726            if(tag.src) return false; // video is loaded
727            var keys = Object.keys(tag.dataset);
728            for(var i = 0;i<keys.length;i++) {
729                if(keys[i].toLowerCase().indexOf("src") > -1) {
730                    var src = tag.dataset[keys[i]];
731                    return src.indexOf('player.vimeo.com/video/') > -1;
732                }
733            }
734            return false; //not find src
735        }
736
737        function attachVimeoPlayerToTag(tag) {
738            var player = new Vimeo.Player(tag);
739
740            player.getDuration().then(function (pl,seconds) {
741                pl.pysMarks = getVideoCompletionMarks(seconds);
742            }.bind(null,player));
743
744            player.getVideoTitle().then(function (pl,title) {
745                pl.pysVideoTitle = title;
746            }.bind(null,player));
747
748            player.getVideoId().then(function (pl,id) {
749                pl.pysVideoId = id;
750            }.bind(null,player));
751
752            player.pysCompletedMarks = {};
753
754            player.on('play', function () {
755
756                if (this.pysTimer) {
757                    return;
758                }
759
760                clearInterval(this.pysTimer);
761
762                var player = this;
763
764                this.pysTimer = setInterval(function () {
765                    checkVimeoCompletion(player);
766                }, 1000);
767
768            });
769
770            player.on('pause', function () {
771                clearInterval(this.pysTimer);
772                this.pysTimer = false;
773            });
774
775            player.on('ended', function () {
776                clearInterval(this.pysTimer);
777                this.pysTimer = false;
778            });
779
780            player.on('playbackratechange', function(data) {
781                var currRate = data.playbackRate;
782                var prevRate = player._pysSpeedRate !== undefined ? player._pysSpeedRate : 1;
783                player._pysSpeedRate = currRate;
784                if(currRate == prevRate) return;
785                if (options.triggerEventTypes && options.triggerEventTypes.video_speed) {
786                    var href = window.location.href;
787                    var vmVideoId = player.pysVideoId ? String(player.pysVideoId) : '';
788                    Object.keys(options.triggerEventTypes.video_speed).forEach(function(evtId) {
789                        var evtConfig   = options.triggerEventTypes.video_speed[evtId];
790                        var urls        = Array.isArray(evtConfig) ? evtConfig : (evtConfig.urls || []);
791                        var speedRate   = Array.isArray(evtConfig) ? 'any' : (evtConfig.speed_rate || 'any');
792                        var evtTriggers = Array.isArray(evtConfig) ? [] : (evtConfig.triggers || []);
793                        var pageOk      = !urls || urls.length === 0 || urls.some(function(u) { return u === '*' || u === '' || href.indexOf(u) !== -1; });
794                        var rateOk      = speedRate === 'any' ? currRate !== prevRate : (speedRate === 'increase' ? currRate > prevRate : currRate < prevRate);
795                        var videoOk     = evtTriggers.length === 0 || evtTriggers.some(function(t) { return t.type === 'vimeo' && t.rule == vmVideoId; });
796                        if (pageOk && rateOk && videoOk) {
797                            Utils.handleTriggerFired(evtId, 'video_speed');
798                        }
799                    });
800                }
801                if (options.dynamicEvents && options.dynamicEvents.automatic_event_video_speed) {
802                    var vimeoEl = player.element || null;
803                    var params = {
804                        video_url: vimeoEl ? (vimeoEl.src || '') : '',
805                        video_type: 'vimeo',
806                        video_title: player.pysVideoTitle || 'Unknown Title',
807                        playback_speed: currRate,
808                        element: 'iframe'
809                    };
810                    Object.keys(options.dynamicEvents.automatic_event_video_speed).forEac
810h(function(slug) {
811                        var pysEvent = Utils.clone(options.dynamicEvents.automatic_event_video_speed[slug]);
812                        Utils.copyProperties(params, pysEvent.params);
813                        var px = getPixelBySlag(slug); if (px) px.fireEvent(pysEvent.name, pysEvent);
814                    });
815                }
816            });
817        }
818
819        // Trigger event if Vimeo video mark was reached
820        function checkVimeoCompletion(player) {
821
822            player.getCurrentTime().then(function (seconds) {
823
824                for (var key in player.pysMarks) {
825
826                    if (player.pysMarks[key] <= seconds && !player.pysCompletedMarks[key]) {
827
828                        player.pysCompletedMarks[key] = true;
829
830                        if (key === '0%') {
831                            key = 'play';
832                        }
833
834                        var params = {
835                            video_type: 'vimeo',
836                            video_id: player.pysVideoId,
837                            video_title: player.pysVideoTitle,
838                        };
839
840                        let disable_watch_video = [];
841
842                        //Custom
843                        if ( options.triggerEventTypes.hasOwnProperty( "video_view" ) ) {
844                            Object.entries( options.triggerEventTypes.video_view ).forEach( function ( [ trigger_id, triggers ] ) {
845                                triggers.forEach( function ( trigger ) {
846                                    if ( trigger.type === 'vimeo' && trigger.rule == player.pysVideoId ) {
847                                        let pixels = Object.keys( options.triggerEvents[ trigger_id ] );
848                                        for ( let i = 0; i < pixels.length; i++ ) {
849                                            let event = Utils.clone( options.triggerEvents[ trigger_id ][ pixels[ i ] ] );
850
851                                            if ( trigger.disable_watch_video ) {
852                                                disable_watch_video.push( pixels[ i ] );
853                                            }
854
855                                            if ( seconds >= player.pysMarks[ trigger.value ] ) {
856												if ( pixels[ i ] !== 'reddit' ) {
857													event.params[ "progress" ] = key;
858													Utils.copyProperties( params, event.params );
859                                                }
860
861                                                if ( event.fired !== true ) {
862                                                    if ( Utils.isEventInTimeWindow( event.name, event, 'dyn_' + pixels[ i ] + '_' + trigger_id ) ) {
863                                                        event = Utils.getFormFilledData( event );
864                                                        getPixelBySlag( pixels[ i ] ).fireEvent( event.name, event );
865                                                        options.triggerEvents[ trigger_id ][ pixels[ i ] ].fired = true;
866                                                    }
867                                                }
868                                            }
869                                        }
870                                    }
871                                } )
872                            } )
873                        }
874
875                        // Auto
876                        if(options.automatic.enable_video
877                            && options.automatic.enable_vimeo
878                            && options.dynamicEvents.hasOwnProperty("automatic_event_video")
879                        ) {
880                            var pixels = Object.keys(options.dynamicEvents.automatic_event_video);
881
882                            for (var i = 0; i < pixels.length; i++) {
883                                if ( disable_watch_video.includes( pixels[ i ] ) ) {
884                                    continue;
885                                }
886
887                                var event = Utils.clone(options.dynamicEvents.automatic_event_video[pixels[i]]);
888
889								if ( pixels[i] !== 'reddit' ) {
890									event.params["progress"] = key;
891									Utils.copyProperties(params, event.params);
892								}
893
894                                if ( pixels[i] === 'tiktok' || pixels[i] === 'reddit' ) {
895                                    var time_trigger = event.automatic_event_video_trigger;
896                                    if ( seconds >= player.pysMarks[time_trigger] && event.fired !== true ) {
897                                        getPixelBySlag(pixels[i]).onWatchVideo(event);
898
899                                        //tiktok and reddit watch video fire once
900                                        options.dynamicEvents.automatic_event_video[pixels[i]].fired = true;
901                                    }
902                                } else {
903                                    Utils.copyProperties(Utils.getRequestParam
903s(), event.params);
904                                    getPixelBySlag(pixels[i]).onWatchVideo(event);
905                                }
906                            }
907                        }
908
909                        if(key == "play") {
910                            $.each(options.triggerEventTypes, function (triggerType, events) {
911                                $.each(events, function (eventId, triggers) {
912                                    switch (triggerType) {
913                                        case 'video_play':
914                                            Utils.handleTriggerFired(eventId, triggerType);
915                                            break;
916                                    }
917
918                                });
919                            });
920                        }
921                    }
922
923                }
924
925            });
926
927        }
928
929        // ── HTML5 <video> WatchVideo tracking ───────────────────────────────────
930        function initHtml5VideoTracking() {
931
932            if ( !options.automatic.enable_video
933                || !options.dynamicEvents.hasOwnProperty('automatic_event_video')
934            ) {
935                return;
936            }
937
938            // play event — fires once per element when playback starts
939            document.addEventListener('play', function (e) {
940                var el = e.target;
941                if ( !el || el.tagName !== 'VIDEO' ) return;
942
943                el.pysCompletedMarks = el.pysCompletedMarks || {};
944                if ( el.pysCompletedMarks['play'] ) return;
945
946                var url = el.src || el.currentSrc || '';
947                el.pysCompletedMarks['play'] = true;
948
949                fireHtml5VideoMilestone( el, url, 'play' );
950
951            }, true );
952
953            // timeupdate — check percentage milestones
954            document.addEventListener('timeupdate', function (e) {
955                var el = e.target;
956                if ( !el || el.tagName !== 'VIDEO' ) return;
957
958                var duration = el.duration;
959                if ( !duration || isNaN(duration) || !isFinite(duration) ) return;
960
961                var currentTime = el.currentTime;
962                var marks = getVideoCompletionMarks( duration );
963                var url   = el.src || el.currentSrc || '';
964
965                el.pysCompletedMarks = el.pysCompletedMarks || {};
966
967                for ( var key in marks ) {
968                    if ( key === '0%' ) continue; // handled by 'play' listener
969
970                    if ( marks[ key ] <= currentTime && !el.pysCompletedMarks[ key ] ) {
971                        el.pysCompletedMarks[ key ] = true;
972                        fireHtml5VideoMilestone( el, url, key );
973                    }
974                }
975
976            }, true );
977        }
978
979        function fireHtml5VideoMilestone( el, url, key ) {
980
981            var progressLabel = ( key === '0%' ) ? 'play' : key;
982
983            var params = {
984                video_type:  'html5',
985                video_id:    el.id || url,
986                video_title: Utils.getHtml5VideoTitle( url ),
987            };
988
989            var pixels = Object.keys( options.dynamicEvents.automatic_event_video );
990
991            for ( var i = 0; i < pixels.length; i++ ) {
992                var event = Utils.clone( options.dynamicEvents.automatic_event_video[ pixels[ i ] ] );
993
994                if ( pixels[ i ] !== 'reddit' ) {
995                    event.params[ 'progress' ] = progressLabel;
996                    Utils.copyProperties( params, event.params );
997                }
998
999                if ( pixels[ i ] === 'tiktok' || pixels[ i ] === 'reddit' ) {
1000                    var time_trigger = event.automatic_event_video_trigger;
1001                    var marks        = getVideoCompletionMarks( el.duration || 0 );
1002                    if ( el.currentTime >= marks[ time_trigger ] && event.fired !== true ) {
1003                        getPixelBySlag( pixels[ i ] ).onWatchVideo( event );
1004                        options.dynamicEvents.automatic_event_video[ pixels[ i ] ].fired = true;
1005                    }
1006                } else {
1007                    Utils.copyProperties( Utils.getRequestParams(), event.params );
1008                    getPixelBySlag( pixels[ i ] ).onWatchVideo( event );
1009                }
1010            }
1011
1012            // handle custom video_view triggers (mirrors YouTube/Vimeo pattern)
1013            if ( key === 'play' ) {
1014                $.each( options.triggerEventTypes, function ( triggerType, events ) {
1015                    $.each( events, function ( eventId ) {
1016                        if ( triggerType === 'video_play' ) {
1017                            Utils.handleTriggerFired( eventId, triggerType );
1018                        }
1019                    } );
1020                } );
1021            }
1022        }
1023
1024        /**
1025         * COOKIES UTILS
1026         */
1027
1028        var utmTerms = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content' ,'utm_term'];
1029        var utmId = ['fbadid', 'gadid', 'padid', 'bingid'];
1030        var requestParams = [];
1031
1032
1033        function getDomain(url) {
1034
1035            url = url.replace(/(https?:\/\/)?(www.)?/i, '');
1036
1037            if (url.indexOf('/') !== -1) {
1038                return url.split('/')[0];
1039            }
1040
1041            return url;
1042        }
1043
1044        function checkSession() {
1045
1046            if( Cookies.get('pys_start_session') === undefined ||
1047                Cookies.get('pys_session_limit') === undefined) {
1048                firstVisit = true;
1049                return true
1050            }
1051            return false
1052
1053        }
1054
1055        function getTrafficSource() {
1056
1057            try {
1058
1059                let referrer = document.referrer.toString(),
1060                    source;
1061
1062                let direct = referrer.length === 0;
1063                let internal = direct ? false : referrer.indexOf(options.siteUrl) === 0;
1064                let external = !direct && !internal;
1065
1066                if (external === false) {
1067                    source = 'direct';
1068                } else {
1069                    source = referrer;
1070                }
1071
1072                if (source !== 'direct') {
1073                    // leave only domain (Issue #70)
1074                    return getDomain(source);
1075                } else {
1076                    return source;
1077                }
1078
1079            } catch (e) {
1080                console.error(e);
1081                return 'direct';
1082            }
1083
1084        }
1085
1086        /**
1087         * Return query variables object with where property name is query variable
1088         * and property value is query variable value.
1089         */
1090        function getQueryVars() {
1091
1092            try {
1093
1094                var result = {},
1095                    tmp = [];
1096
1097                window.location.search
1098                    .substr(1)
1099                    .split("&")
1100                    .forEach(function (item) {
1101
1102                        tmp = item.split('=');
1103
1104                        if (tmp.length > 1) {
1105                            result[tmp[0]] = tmp[1];
1106                        }
1107
1108                    });
1109
1110                return result;
1111
1112            } catch (e) {
1113                console.error(e);
1114                return {};
1115            }
1116
1117        }
1118
1119        function getLandingPageValue() {
1120            let name = "pys_landing_page"
1121            if(options.visit_data_model === "last_visit") {
1122                name = "last_pys_landing_page"
1123            }
1124            if(Cookies.get(name) && Cookies.get(name) !== "undefined") {
1125                return Cookies.get(name);
1126            }
1127            else if(options.hasOwnProperty("tracking_analytics") && options.tracking_analytics.TrafficLanding){
1128                return options.tracking_analytics.TrafficLanding;
1129            } else{
1130                return "";
1131            }
1132        }
1133        function getTrafficSourceValue() {
1134            let name = "pysTrafficSource"
1135            if(options.visit_data_model === "last_visit") {
1136                name = "last_pysTrafficSource"
1137            }
1138            if(Cookies.get(name) && Cookies.get(name) !== "undefined") {
1139                return Cookies.get(name);
1140            } else{
1141                return "";
1142            }
1143        }
1144
1145        /**
1146         * Handle alternative GCLID parameter for Safari compatibility
1147         * Creates _gcl_aw cookie when alternative parameter is detected and _gcl_aw doesn't exist
1148         */
1149        function handleAlternativeGclid() {
1150            // Check if alternative GCLID is enabled
1151            if (!options.GATags || !options.GATags.gclid_alternative_enabled || !options.GATags.gclid_alternative_param) {
1152                return;
1153            }
1154
1155            // GDPR consent checks - stop if any consent filter blocks it
1156            if (options.gdpr.all_disabled_by_api) {
1157                return;
1158            }
1159            if (options.gdpr.analytics_disabled_by_api) {
1160                return;
1161            }
1162            if (options.cookie.disabled_all_cookie) {
1163                return;
1164            }
1165            if (options.cookie.disabled_google_alternative_id) {
1166                return;
1167            }
1168
1169            const alternativeParam = options.GATags.gclid_alternative_param;
1170            const queryVars = getQueryVars();
1171            
1172            // Check if alternative parameter exists in URL
1173            if (queryVars[alternativeParam]) {
1174                const gclidValue = queryVars[alternativeParam];
1175                
1176                // Only create _gcl_aw cookie if it doesn't exist
1177                if (!Cookies.get('_gcl_aw')) {
1178                    // Create _gcl_aw cookie with the alternative parameter value in Google's format
1179                    // Format: GCL.{timestamp}.{gclid_value}
1180                    const timestamp = Math.floor(Date.now() / 1000);
1181                    const cookieValue = 'GCL.' + timestamp + '.' + gclidValue;
1182                    
1183                    // Set cookie for 90 days (Google's standard)
1184                    const expires = new Date();
1185                    expires.setTime(expires.getTime() + (90 * 24 * 60 * 60 * 1000));
1186                    
1187                    Cookies.set('_gcl_aw', cookieValue, { 
1188                        expires: expires, 
1189                        path: '/', 
1190                        domain: domain 
1191                    });
1192                    
1193                    if (options.debug) {
1194                        console.log('PYS: Created _gcl_aw cookie from alternative parameter:', alternativeParam, '=', gclidValue);
1195                    }
1196                }
1197            }
1198        }
1199
1200        function getUTMId(useLast = false) {
1201            try {
1202                let cookiePrefix = 'pys_'
1203                let terms = [];
1204                if (useLast) {
1205                    cookiePrefix = 'last_pys_'
1206                }
1207                $.each(utmId, function (index, name) {
1208                    if (Cookies.get(cookiePrefix + name)) {
1209                        terms[name] = Cookies.get(cookiePrefix + name)
1210                    }
1211                    else if(options.hasOwnProperty("tracking_analytics") && options.tracking_analytics.TrafficUtmsId[name]) {
1212                        terms[name] = filterEmails(options.tracking_analytics.TrafficUtmsId[name])
1213                    }
1214                });
1215                return terms;
1216            } catch (e) {
1217                console.error(e);
1218                return [];
1219            }
1220        }
1221        /**
1222         * Return UTM terms from request query variables or from cookies.
1223         */
1224        function getUTMs(useLast = false) {
1225
1226            try {
1227                let cookiePrefix = 'pys_'
1228                if(useLast) {
1229                    cookiePrefix = 'last_pys_'
1230                }
1231                let terms = [];
1232                $.each(utmTerms, function (index, name) {
1233                    if (Cookies.get(cookiePrefix + name)) {
1234                        let value = Cookies.get(cookiePrefix + name);
1235                        terms[name] = filterEmails(value); // do not allow email in request params (Issue #70)
1236                    }
1237                    else if(options.hasOwnProperty("tracking_analytics") && options.tracking_analytics.TrafficUtms[name]) {
1238                        terms[name] = filterEmails(options.tracking_analytics.TrafficUtms[name])
1239                    }
1240                });
1241
1242                return terms;
1243
1244            } catch (e) {
1245                console.error(e);
1246                return [];
1247            }
1248
1249        }
1250
1251        function getDateTime() {
1252            var dateTime = new Array();
1253            var date = new Date(),
1254                days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
1255                months = ['January', 'February', 'March', 'April', 'May', 'June',
1256                    'July', 'August', 'September', 'October', 'November', 'December'
1257                ],
1258                hours = ['00-01', '01-02', '02-03', '03-04', '04-05', '05-06', '06-07', '07-08',
1259                    '08-09', '09-10', '10-11', '11-12', '12-13', '13-14', '14-15', '15-16', '16-17',
1260                    '17-18', '18-19', '19-20', '20-21', '21-22', '22-23', '23-24'
1261                ];
1262            dateTime.push(hours[date.getHours()]);
1263            dateTime.push(days[date.getDay()]);
1264            dateTime.push(months[date.getMonth()]);
1265            return dateTime;
1266        }
1267
1268        function filterEmails(value) {
1269            return Utils.validateEmail(value) ? undefined : value;
1270        }
1271
1272        /**
1273         * PUBLIC API
1274         */
1275        return {
1276
1277            PRODUCT_SIMPLE : 0,
1278            PRODUCT_VARIABLE : 1,
1279            PRODUCT_BUNDLE : 2,
1280            PRODUCT_GROUPED : 3,
1281            utmTerms : utmTerms,
1282            utmId : utmId,
1283            isNewSession: checkSession(),
1284            setHidePixelCookie: function(){
1285                let refresh_after_consent = false;
1286                if ( !firstVisit && options.gdpr.consent_magic_integration_enabled && window.CS_Data !== undefined && window.CS_Data.cs_refresh_after_consent) {
1287                    refresh_after_consent = true;
1288                }
1289                if( !refresh_after_consent && !firstVisit) return false;
1290
1291                const url_parts = window.location.href;
1292                const url_params = new URLSearchParams(window.location.search);
1293                const matchingPixels = ["facebook", "ga", "gtm", "google_ads", "bing", "pinterest", "tiktok", "reddit"];
1294                $.each(matchingPixels, function (index, slug) {
1295                    var module = getPixelBySlag(slug);
1296                    if (module && module.isEnabled()) {
1297                        const fullUrl = window.location.href;
1298                        $.each(module.getHidePixel(), function (index, hide_info) {
1299                            for (const item of hide_info.hide_tag_contain) {
1300                                if (item && fullUrl.includes(item)) {
1301                                    let hideTagTimeInMilliseconds = hide_info.hide_tag_time * 60 * 60 * 1000;
1302                                    let expiresTime = new Date().getTime() + hideTagTimeInMilliseconds;
1303                                    Cookies.set('hide_tag_' + hide_info.pixel, true, { expires: new Date(expiresTime), path: '/' });
1304                                    break;
1305                                }
1306                            }
1307                        });
1308                    }
1309
1310                });
1311            },
1312            hideMatchingPixel: function(pixelValue, slug) {
1313                if(Cookies.get('hide_tag_'+pixelValue))
1314                {
1315                    return true;
1316                }
1317                return false;
1318            },
1319            validateEmail: function (email) {
1320                var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
1321                return re.test(email);
1322            },
1323            fireEventForAllPixel:function(functionName,events){
1324                if (events.hasOwnProperty(Facebook.tag()))
1325                    Facebook[functionName](events[Facebook.tag()]);
1326                if (events.hasOwnProperty(Analytics.tag()))
1327                    Analytics[functionName](events[Analytics.tag()]);
1328                if (events.hasOwnProperty(GAds.tag()))
1329                    GAds[functionName](events[GAds.tag()]);
1330                if (events.hasOwnProperty(Pinterest.tag()))
1331                    Pinterest[functionName](events[Pinterest.tag()]);
1332                if (events.hasOwnProperty(Bing.tag()))
1333                    Bing[functionName](events[Bing.tag()]);
1334                if (events.hasOwnProperty(TikTok.tag()))
1335                    TikTok[functionName](events[TikTok.tag()]);
1336	            if (events.hasOwnProperty(Reddit.tag()))
1337		            Reddit[functionName](events[Reddit.tag()]);
1338
1339                if (events.hasOwnProperty(GTM.tag()))
1340                    GTM[functionName](events[GTM.tag()]);
1341            },
1342
1343            getQueryValue:function (name){
1344                return getQueryVars()[name];
1345            },
1346
1347            filterEmails: function (value) {
1348                return filterEmails(value);
1349            },
1350
1351            setupPinterestObject: function () {
1352                Pinterest = window.pys.Pinterest || Pinterest;
1353                return Pinterest;
1354            },
1355
1356            setupBingObject: function () {
1357                Bing = window.pys.Bing || Bing;
1358                return Bing;
1359            },
1360
1361	        setupRedditObject: function () {
1362		        Reddit = window.pys.Reddit || Reddit;
1363		        return Reddit;
1364	        },
1365
1366            // Clone all object members to another and return it
1367            copyProperties: function (from, to) {
1368                for (var key in from) {
1369                    if("function" == typeof from[key]) {
1370                        continue;
1371                    }
1372                    to[key] = from[key];
1373                }
1374                return to;
1375            },
1376
1377            getVideoTypeFromUrl: function (url) {
1378                if (!url) return 'unknown';
1379                if (url.indexOf('youtube.com') !== -1 || url.indexOf('youtu.be') !== -1) return 'youtube';
1380                if (url.indexOf('vimeo.com') !== -1) return 'vimeo';
1381                return 'html5';
1382            },
1383
1384            getHtml5VideoTitle: function (url) {
1385                if (!url) return 'Unknown Title';
1386                var path = url.split('?')[0].split('#')[0];
1387                var filename = path.split('/').pop();
1388                if (!filename) return 'Unknown Title';
1389                var ext = filename.lastIndexOf('.');
1390                return ext > 0 ? filename.slice(0, ext) : filename;
1391            },
1392
1393            /**
1394             * Generate unique ID
1395             *
1396             * For purchase events (woo_purchase, edd_purchase):
1397             * - Server eventID has priority (for server-browser deduplication)
1398             * - If server didn't provide eventID, generate one keyed by order_id
1399             *
1400             * For other events:
1401             * - Use existing logic with event type as key
1402             */
1403            generateUniqueId : function (event) {
1404                var eventsWithHook = [
1405                    'woo_purchase',
1406                    'woo_start_trial',
1407                    'woo_subscription_created',
1408                    'woo_subscription_renewal',
1409                    'edd_purchase',
1410                    'edd_start_trial',
1411                    'edd_subscription_created',
1412                    'edd_subscription_renewal',
1413                    'edd_license_created',
1414                    'edd_license_upgrade',
1415                    'edd_license_renewal'
1416                ];
1417
1418                // For events with server hooks: prioritize server eventID
1419                if ( eventsWithHook.includes( event.e_id ) ) {
1420                    // If server provided eventID, use it (for deduplication)
1421                    if ( event.eventID && event.eventID.length > 0 ) {
1422                        var orderKey = event.e_id;
1423                        if ( !uniqueId.hasOwnProperty( orderKey ) ) {
1424                            uniqueId[orderKey] = event.eventID;
1425                        }
1426                        return uniqueId[orderKey];
1427                    }
1428                }
1429
1430                if (
1431                    event.eventID.length == 0 ||
1432                    ( !event.isVariationTrigger &&
1433                        ( event.type == "static" && options.ajaxForServerStaticEvent ||
1434                          event.type !== "static" && options.ajaxForServerEvent )
1435                    )
1436                ) {
1437                    let idKey = event.hasOwnProperty('custom_event_post_id') ? event.custom_event_post_id : event.e_id;
1438                    if ( !uniqueId.hasOwnProperty( idKey ) ) {
1439                        uniqueId[idKey] = pys_generate_token();
1440                    }
1441                    return uniqueId[idKey];
1442                }
1443                else if ( event.eventID.length !== 0 ) {
1444                    return event.eventID;
1445                }
1446            },
1447
1448            // Flatten object for sendBeacon compatibility
1449            flattenObject: function (obj, prefix = '', res = {}) {
1450                for (const [key, value] of Object.entries(obj)) {
1451                    const prefixedKey = prefix
1452                        ? (Array.isArray(obj) ? `${prefix}[${key}]` : `${prefix}[${key}]`)
1453                        : key;
1454                    if (value !== null && typeof value === 'object' && !(value instanceof File)) {
1455                        this.flattenObject(value, prefixedKey, res);
1456                    } else {
1457                        res[prefixedKey] = value;
1458                    }
1459                }
1460                return res;
1461            },
1462
1463            sendServerAjaxRequest: function ( url, data ) {
1464                // Check if we should use REST API for TikTok or Facebook
1465                if (data.action === 'pys_tiktok_api_event' && window.pysTikTokRest) {
1466                    // Use TikTok REST API
1467                    this.sendRestAPIRequest(data, 'tiktok');
1468                    return;
1469                }
1470
1471                if (data.action === 'pys_api_event' && data.pixel === 'facebook' && window.pysFacebookRest) {
1472                    // Use Facebook REST API
1473                    this.sendRestAPIRequest(data, 'facebook');
1474                    return;
1475                }
1476
1477                // Check if sendBeacon is enabled and supported
1478                if (options.useSendBeacon && navigator.sendBeacon) {
1479                    try {
1480                        // Flatten the data object for sendBeacon compatibility
1481                        const flattenedData = this.flattenObject(data);
1482                        const formData = new URLSearchParams();
1483
1484                        // Convert flattened data to URLSearchParams
1485                        for (const [key, value] of Object.entries(flattenedData)) {
1486                            if (value !== null && value !== undefined) {
1487                                formData.append(key, value);
1488                            }
1489                        }
1490
1491                        // Try to send using sendBeacon
1492                        const success = navigator.sendBeacon(url, formData);
1493                        if (success) {
1494                            return; // Successfully sent via sendBeacon
1495                        }
1496                    } catch (e) {
1497                        // If sendBeacon fails, fall back to jQuery.ajax
1498                        if (options.debug) {
1499                            console.log('PYS: sendBeacon failed, falling back to jQuery.ajax:', e);
1500                        }
1501                    }
1502                }
1503
1504                // Fallback to jQuery.ajax
1505                jQuery.ajax( {
1506                    type: 'POST',
1507                    url: url,
1508                    data: data,
1509                    headers: {
1510                        'Cache-Control': 'no-cache'
1511                    },
1512                    success: function () {
1513                    },
1514                } );
1515            },
1516
1517            // Send event via REST API (unified function for TikTok, Facebook, and other platforms)
1518            // Replaces the old sendTikTokRestAPIRequest and sendFacebookRestAPIRequest functions
1519            sendRestAPIRequest: function (data, platform) {
1520                let restApiUrl;
1521
1522                // Get platform-specific REST API configuration
1523                switch (platform) {
1524                    case 'tiktok':
1525                        restApiUrl = window.pysTikTokRest ? window.pysTikTokRest.restApiUrl : '/wp-json/pys-tiktok/v1/event';
1526                        break;
1527                    case 'facebook':
1528                        restApiUrl = window.pysFacebookRest ? window.pysFacebookRest.restApiUrl : '/wp-json/pys-facebook/v1/event';
1529                        break;
1530                    case 'pinterest':
1531                        restApiUrl = window.pysPinterestRest ? window.pysPinterestRest.restApiUrl : '/wp-json/pys-pinterest/v1/event';
1532                        break;
1533                    default:
1534                        console.error('PYS: Unknown platform for REST API:', platform);
1535                        this.sendAjaxFallback(data);
1536                        return;
1537                }
1538
1539                // Prepare data for REST API
1540                const restApiData = {
1541                    event: data.event,
1542                    event_slug: data.event_slug,
1543                    data: JSON.stringify(data.data || {}),
1544                    ids: JSON.stringify(data.ids || []),
1545                    eventID: data.event_id || data.eventID || '',
1546                    woo_order: data.woo_order || '0',
1547                    edd_order: data.edd_order || '0'
1548                };
1549
1550                // Try to send using sendBeacon first (if enabled)
1551                if (options.useSendBeacon && navigator.sendBeacon) {
1552                    try {
1553                        const formData = new URLSearchParams();
1554                        for (const [key, value] of Object.entries(restApiData)) {
1555                            formData.append(key, value);
1556                        }
1557
1558                        if (navigator.sendBeacon(restApiUrl, formData)) {
1559                            return;
1560                        }
1561                    } catch (e) {
1562                        // sendBeacon failed, continue to fetch
1563                    }
1564                }
1565
1566                // Try to send using fetch with REST API
1567                if (window.fetch) {
1568                    const headers = {
1569                        'Content-Type': 'application/json'
1570                    };
1571
1572                    fetch(restApiUrl, {
1573                        method: 'POST',
1574                        headers: headers,
1575                        body: JSON.stringify(restApiData)
1576                    })
1577                    .then(response => {
1578                        if (!response.ok) {
1579                            throw new Error(platform + ' REST API request failed: ' + response.status);
1580                        }
1581                    })
1582                    .catch(error => {
1583                        // Fallback to AJAX if REST API fails
1584                        if (options.debug) {
1585                            console.log('PYS: ' + platform + ' REST API failed, falling back to AJAX:', error);
1586                        }
1587                        this.sendAjaxFallback(data);
1588                    });
1589                } else {
1590                    // Fallback to AJAX if fetch is not supported
1591                    this.sendAjaxFallback(data);
1592                }
1593            },
1594
1595
1596
1597            // Fallback AJAX method
1598            sendAjaxFallback: function (data) {
1599                jQuery.ajax({
1600                    type: 'POST',
1601                    url: options.ajaxUrl,
1602                    data: data,
1603                    headers: {
1604                        'Cache-Control': 'no-cache'
1605                    },
1606                    success: function () {
1607                    },
1608                });
1609            },
1610
1611            clone: function(obj) {
1612                var copy;
1613
1614                // Handle the 3 simple types, and null or undefined
1615                if (null == obj || "object" != typeof obj) return obj;
1616
1617                // Handle Date
1618                if (obj instanceof Date) {
1619                    copy = new Date();
1620                    copy.setTime(obj.getTime());
1621                    return copy;
1622                }
1623
1624                // Handle Array
1625                if (obj instanceof Array) {
1626                    copy = [];
1627                    for (var i = 0, len = obj.length; i < len; i++) {
1628                        if("function" == typeof obj[i]) {
1629                            continue;
1630                        }
1631                        copy[i] = Utils.clone(obj[i]);
1632                    }
1633                    return copy;
1634                }
1635
1636                // Handle Object
1637                if (obj instanceof Object) {
1638                    copy = {};
1639                    for (var attr in obj) {
1640                        if (obj.hasOwnProperty(attr)) {
1641                            if("function" == typeof obj[attr]) {
1642                                continue;
1643                            }
1644                            copy[attr] = Utils.clone(obj[attr]);
1645                        }
1646                    }
1647                    return copy;
1648                }
1649
1650                return obj;
1651            },
1652
1653            // Returns array of elements with given tag name
1654            getTagsAsArray: function (tag) {
1655                return [].slice.call(document.getElementsByTagName(tag));
1656            },
1657
1658
1659            initializeVideoAPIs: function (options) {
1660                let trigger_has_video_YT, trigger_has_video_Vimeo = false;
1661                if (options.hasOwnProperty('automatic') && options.automatic.enable_video) {
1662                    if ( options.triggerEventTypes.hasOwnProperty( "video_view" ) ) {
1663                        Object.entries( options.triggerEventTypes.video_view ).forEach( function ( [ trigger_id, triggers ] ) {
1664                            triggers.forEach( function ( trigger ) {
1665                                if (trigger.type === 'youtube') {
1666                                    trigger_has_video_YT = true;
1667                                }
1668                                if(trigger.type === 'vimeo'){
1669                                    trigger_has_video_Vimeo = true;
1670                                }
1671                            });
1672                        });
1673                    }
1674                    if (
1675                        options.hasOwnProperty('enable_automatic_events') &&
1676                        options.enable_automatic_events
1677                    ) {
1678                        if (options.automatic.enable_youtube || trigger_has_video_YT) {
1679                            Utils.initYouTubeAPI();
1680                        }
1681                        if (options.automatic.enable_vimeo || trigger_has_video_Vimeo) {
1682                            Utils.initVimeoAPI();
1683                        }
1684                        initHtml5VideoTracking();
1685                    }
1686                }
1687
1688                // Also init YT/Vimeo APIs for video_speed custom triggers and global VideoSpeed event
1689                var has_video_speed_trigger = options.triggerEventTypes && options.triggerEventTypes.hasOwnProperty('video_speed') &&
1690                    Object.keys(options.triggerEventTypes.video_speed).length > 0;
1691                var has_global_video_speed = options.dynamicEvents && options.dynamicEvents.hasOwnProperty('automatic_event_video_speed');
1692                if (has_video_speed_trigger || has_global_video_speed) {
1693                    Utils.initYouTubeAPI();
1694                    Utils.initVimeoAPI();
1695                }
1696            },
1697            /**
1698             * Load and initialize YouTube API
1699             *
1700             * @link: https://developers.google.com/youtube/iframe_api_reference
1701             */
1702            initYouTubeAPI: function () {
1703
1704                // maybe load YouTube JS API
1705                if (typeof window.YT === 'undefined') {
1706                    var tag = document.createElement('script');
1707                    tag.src = '//www.youtube.com/iframe_api';
1708                    var firstScriptTag = document.getElementsByTagName('script')[0];
1709                    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
1710                }
1711
1712                // initialize when API is ready
1713                if ( typeof window.onYouTubeIframeAPIReady !== 'function' ) {
1714
1715                    window.onYouTubeIframeAPIReady = function () {
1716
1717                        // collect all possible YouTube tags
1718                        var potentialVideos = Utils.getTagsAsArray( 'iframe' ).concat( 
1718Utils.getTagsAsArray( 'embed' ) );
1719
1720                        // turn videos into trackable videos with events
1721                        for ( var i = 0; i < potentialVideos.length; i++ ) {
1722                            var video = potentialVideos[ i ];
1723                            if ( tagIsYouTubeVideo( video ) ) {
1724                                var iframe = normalizeYouTubeIframe( video );
1725                                addYouTubeEvents( iframe );
1726                            } else if ( tagIsYouTubeAsyncVideo( video ) ){
1727                                video.addEventListener( "load", function ( evt ) {
1728                                    var iframe = normalizeYouTubeIframe( evt.currentTarget );
1729                                    addYouTubeEvents( iframe );
1730                                } );
1731                            }
1732                        }
1733
1734                        var targets = document.querySelectorAll( '.elementor-widget-video .elementor-wrapper' );
1735
1736                        const config = {
1737                            attributes: false,
1738                            childList: true,
1739                            subtree: true
1740                        };
1741
1742                        const callback = function ( mutationsList, observer ) {
1743                            for ( let mutation of mutationsList ) {
1744                                if ( mutation.type === 'childList' ) {
1745                                    for ( var m = 0; m < mutation.addedNodes.length; m++ ) {
1746                                        addDynYouTubeVideos( mutation.addedNodes[ m ] );
1747                                    }
1748                                }
1749                            }
1750                        };
1751                        // observe elementator widget-video and add event when it add iframe
1752                        for ( var i = 0; i < targets.length; i++ ) {
1753                            const observer = new MutationObserver( callback );
1754                            observer.observe( targets[ i ], config );//maybe remove before add
1755                        }
1756                    }
1757                }
1758            },
1759
1760            /**
1761             * Load and initialize Vimeo API
1762             *
1763             * @link: https://github.com/vimeo/player.js
1764             */
1765            initVimeoAPI: function () {
1766
1767
1768                $(document).ready(function () {
1769
1770                    var potentialVideos = Utils.getTagsAsArray('iframe').concat(Utils.getTagsAsArray('embed'));
1771
1772                    for (var i = 0; i < potentialVideos.length; i++) {
1773                        var tag = potentialVideos[i];
1774                        if (tagIsVimeoVideo(tag)) {
1775                            var nextElementHasClass = $(tag).closest('.elementor-widget-video').find('.elementor-custom-embed-image-overlay');
1776                            if(nextElementHasClass.length > 0) {
1777                                tag.addEventListener("load", function() {
1778                                    attachVimeoPlayerToTag(this);
1779                                });
1780                            }
1781                            else {
1782                                attachVimeoPlayerToTag(tag);
1783                            }
1784
1785
1786                        } else {
1787                            if (tagIsAsincVimeoVideo(tag)) {
1788                                tag.addEventListener("load", function(evt) {
1789                                    attachVimeoPlayerToTag(evt.currentTarget);
1790                                });
1791                            }
1792                        }
1793                    }
1794
1795                });
1796
1797            },
1798
1799            manageCookies: function () {
1800                // Handle alternative GCLID parameter for Safari compatibility
1801                handleAlternativeGclid();
1802                
1803                if (options.gdpr.cookiebot_integration_enabled && typeof Cookiebot !== 'undefined') {
1804                    if (Cookiebot.consented === false && !Cookiebot.consent['marketing'] && !Cookiebot.consent['statistics']) {
1805                        return;
1806                    }
1807                }
1808
1809                let cm_consent_not_expressed = false;
1810                if ( options.gdpr.consent_magic_integration_enabled && window.CS_Data !== undefined && window.CS_Data.cs_refresh_after_consent == 1 ) {
1811                    if ( Cookies.get( 'cs_viewed_cookie_policy' ) === undefined ) {
1812                        cm_consent_not_expressed = true;
1813                    }
1814                }
1815
1816                if( !cm_consent_not_expressed && isNewSession && !options.cookie.disabled_all_cookie && !options.cookie.disabled_start_session_cookie) {
1817                    let duration = options.last_visit_duration * 60000
1818                    var now = new Date();
1819                    now.setTime(now.getTime() + duration);
1820                    Cookies.set('pys_session_limit', true,{ expires: now, path: '/',domain: domain })
1821                    Cookies.set('pys_start_session', true,{ path: '/',domain: domain });
1822                    Utils.setHidePixelCookie();
1823                }
1824
1825                if (!Cookies.get('pbid') && Facebook.isEnabled() && options.ajaxForServerEvent) {
1826                    jQuery.ajax({
1827                        url: options.ajaxUrl,
1828                        dataType: 'json',
1829                        data: {
1830                            action: 'pys_get_pbid'
1831                        },
1832                        success: function (res) {
1833                            if (res.data && res.data.pbid != false && options.send_external_id) {
1834                                if(!(options.cookie.disabled_all_cookie || options.cookie.externalID_disabled_by_api)){
1835                                    var expires = parseInt(options.external_id_expire || 180);
1836                                    Cookies.set('pbid', res.data.pbid, { expires: expires,path: '/',domain: domain });
1837                                }
1838
1839                                if(options.hasOwnProperty('facebook')) {
1840                                    options.facebook.advancedMatching = {
1841                                        ...options.facebook.advancedMatching,  // spread current advancedMatching values
1842                                        external_id: res.data.pbid
1843                                    };
1844                                }
1845                            }
1846                        }
1847                    });
1848                } else if (Cookies.get('pbid') && Facebook.isEnabled()){
1849                    if(options.hasOwnProperty('facebook')) {
1850                        options.facebook.advancedMatching = {
1851                            ...options.facebook.advancedMatching,
1852                            external_id: Cookies.get('pbid')
1853                        };
1854                    }
1855                }
1856                let expires = parseInt(options.cookie_duration); //  days
1857                let queryVars = getQueryVars();
1858                let landing = window.location.href;
1859                try {
1860                    // save data for first visit
1861                    if(Cookies.get('pys_first_visit') === undefined && (!options.cookie.disabled_all_cookie)) {
1862
1863                        if(!options.cookie.disabled_first_visit_cookie)
1864                        {
1865                            Cookies.set('pys_first_visit', true, { expires: expires, path: '/',domain: domain });
1866                        }
1867                        else {
1868                            Cookies.remove('pys_first_visit', { path: '/',domain: domain } )
1869                        }
1870
1871                        if(!options.cookie.disabled_trafficsource_cookie)
1872                        {
1873                            Cookies.set('pysTrafficSource', getTrafficSource(), { expires: expires,path: '/',domain: domain });
1874                        }
1875                        else {
1876                            Cookies.remove('pysTrafficSource', { path: '/',domain: domain })
1877                        }
1878
1879                        if(!options.cookie.disabled_landing_page_cookie && options.enable_lading_page_param)
1880                        {
1881                            Cookies.set('pys_landing_page',landing,{ expires: expires,path: '/',domain: domain });
1882                        }
1883                        else {
1884                            Cookies.remove('pys_landing_page', { path: '/',domain: domain })
1885                        }
1886
1887                        if(!options.cookie.disabled_utmTerms_cookie)
1888                        {
1889                            $.each(utmTerms, function (index, name) {
1890                                if (queryVars.hasOwnProperty(name)) {
1891                                    Cookies.set('pys_' + name, queryVars[name], { expires: expires,path: '/',domain: domain });
1892                                } else {
1893                                    Cookies.remove('pys_' + name, { path: '/',domain: domain })
1894                                }
1895                            });
1896                        }
1897                        else {
1898                            $.each(utmTerms, function (index, name) {
1899                                Cookies.remove('pys_' + name, { path: '/',domain: domain })
1900                            });
1901                        }
1902
1903                        if(!options.cookie.disabled_utmId_cookie)
1904                        {
1905                            $.each(utmId,function(index,name) {
1906                                if (queryVars.hasOwnProperty(name)) {
1907                                    Cookies.set('pys_' + name, queryVars[name], { expires: expires,path: '/',domain: domain });
1908                                } else {
1909                                    Cookies.remove('pys_' + name, { path: '/',domain: domain })
1910                                }
1911                            })
1912                        }
1913                        else {
1914                            $.each(utmId, function (index, name) {
1915                                Cookies.remove('pys_' + name, { path: '/',domain: domain })
1916                            });
1917                        }
1918
1919                    }
1920                    // save data for last visit if it new session
1921                    if(isNewSession && (!options.cookie.disabled_all_cookie)) {
1922                        if(!options.cookie.disabled_trafficsource_cookie)
1923                        {
1924                            Cookies.set('last_pysTrafficSource', getTrafficSource(), { expires: expires,path: '/',domain: domain });
1925                        }
1926                        else {
1927                            Cookies.remove('last_pysTrafficSource', { path: '/',domain: domain })
1928                        }
1929
1930                        if(!options.cookie.disabled_landing_page_cookie && options.enable_lading_page_param)
1931                        {
1932                            Cookies.set('last_pys_landing_page',landing,{ expires: expires,path: '/',domain: domain });
1933                        }
1934                        else {
1935                            Cookies.remove('last_pys_landing_page', { path: '/',domain: domain })
1936                        }
1937
1938                        if(!options.cookie.disabled_utmTerms_cookie)
1939                        {
1940                            $.each(utmTerms, function (index, name) {
1941                                if (queryVars.hasOwnProperty(name)) {
1942                                    Cookies.set('last_pys_' + name, queryVars[name], { expires: expires,path: '/',domain: domain });
1943                                }
1944                            });
1945                        }
1946                        else {
1947                            $.each(utmTerms, function (index, name) {
1948                                Cookies.remove('last_pys_' + name, { path: '/',domain: domain })
1949                            });
1950                        }
1951
1952                        if(!options.cookie.disabled_utmId_cookie)
1953                        {
1954                            $.each(utmId,function(index,name) {
1955                                if (queryVars.hasOwnProperty(name)) {
1956                                    Cookies.set('last_pys_' + name, queryVars[name], { expires: expires,path: '/',domain: domain });
1957                                }
1958                            })
1959                        }
1960                        else {
1961                            $.each(utmId, function (index, name) {
1962                                Cookies.remove('last_pys_' + name, { path: '/',domain: domain })
1963                            });
1964                        }
1965
1966                    }
1967                    if(options.cookie.disabled_start_session_cookie) {
1968                        Cookies.remove('pys_start_session', { path: '/',domain: domain })
1969                        Cookies.remove('pys_session_limit', { path: '/',domain: domain })
1970                    }
1971                    if(options.cookie.disabled_all_cookie)
1972                    {
1973                        Cookies.remove('pys_first_visit', { path: '/',domain: domain })
1974                        Cookies.remove('pysTrafficSource', { path: '/',domain: domain })
1975                        Cookies.remove('pys_landing_page', { path: '/',domain: domain })
1976                        Cookies.remove('last_pys_landing_page', { path: '/',domain: domain })
1977                        Cookies.remove('last_pysTrafficSource', { path: '/',domain: domain })
1978                        Cookies.remove('pys_start_session', { path: '/',domain: domain })
1979                        Cookies.remove('pys_session_limit', { path: '/',domain: domain })
1980                        $.each(Utils.utmTerms, function (index, name) {
1981                            Cookies.remove('pys_' + name, { path: '/',domain: domain })
1982                        });
1983                        $.each(Utils.utmId,function(index,name) {
1984                            Cookies.remove('pys_' + name, { path: '/',domain: domain })
1985                        })
1986                        $.each(Utils.utmTerms, function (index, name) {
1987                            Cookies.remove('last_pys_' + name, { path: '/',domain: domain })
1988                        });
1989                        $.each(Utils.utmId,function(index,name) {
1990                            Cookies.remove('last_pys_' + name, { path: '/',domain: domain })
1991                        });
1992                    }
1993                } catch (e) {
1994                    console.error(e);
1995                }
1996            },
1997
1998            initializeRequestParams: function () {
1999
2000                if (options.trackTrafficSource) {
2001                    requestParams.traffic_source = getTrafficSourceValue();
2002                }
2003
2004                if (options.trackUTMs) {
2005
2006                    var utms = getUTMs(options.visit_data_model === "last_visit");
2007
2008                    $.each(utmTerms, function (index, term) {
2009                        if (term in utms) {
2010                            requestParams[term] = utms[term];
2011                        }
2012                    });
2013
2014                }
2015
2016
2017                var dateTime = getDateTime();
2018                if(options.enable_event_time_param) {
2019                    requestParams.event_hour = dateTime[0];
2020                }
2021
2022                if(options.enable_event_day_param) {
2023                    requestParams.event_day = dateTime[1];
2024                }
2025                if(options.enable_event_month_param) {
2026                    requestParams.event_month = dateTime[2];
2027                }
2028
2029                if(options.enable_lading_page_param){
2030                    requestParams.landing_page = getLandingPageValue().split('?')[0];
2031                }
2032            },
2033
2034            getRequestParams: function () {
2035                return requestParams;
2036            },
2037
2038            /**
2039             * DOWNLOAD DOCS
2040             */
2041
2042            getLinkExtension: function (link) {
2043
2044                // Remove anchor, query string and everything before last slash
2045                link = link.substring(0, (link.indexOf("#") === -1) ? link.length : link.indexOf("#"));
2046                link = link.substring(0, (link.indexOf("?") === -1) ? link.length : link.indexOf("?"));
2047                link = link.substring(link.lastIndexOf("/") + 1, link.length);
2048
2049                // If there's a period left in the URL, then there's a extension
2050                if (link.length > 0 && link.indexOf('.') !== -1) {
2051                    link = link.substring(link.lastIndexOf(".") + 1); // Remove everything but what's after the first period
2052                    return link;
2053                } else {
2054                    return "";
2055                }
2056            },
2057
2058            getLinkFilename: function (link) {
2059
2060                // Remove anchor, query string and everything before last slash
2061                link = link.substring(0, (link.indexOf("#") === -1) ? link.length : link.indexOf("#"));
2062                link = link.substring(0, (link.indexOf("?") === -1) ? link.length : link.indexOf("?"));
2063                link = link.substring(link.lastIndexOf("/") + 1, link.length);
2064
2065                // If there's a period left in the URL, then there's a extension
2066                if (link.length > 0 && link.indexOf('.') !== -1) {
2067                    return link;
2068                } else {
2069                    return "";
2070                }
2071            },
2072
2073            /**
2074             * CUSTOM EVENTS
2075             */
2076
2077            setupMouseOverClickEvents: function (eventId, triggers, triggerType) {
2078
2079                // Non-default binding used to avoid situations when some code in external js
2080                // stopping events propagation, eg. returns false, and our handler will never called
2081                document.addEventListener('mouseover', function(event) {
2082                    var matchedElements = Array.from(document.querySelectorAll(triggers));
2083                    var clickedElement = event.target;
2084                    var closestMatch = clickedElement.closest(triggers);
2085                    if (matchedElements.includes(clickedElement) || closestMatch){
2086                        if (event.target.classList.contains('pys-mouse-over-' + eventId)) {
2087                            return true;
2088                        } else {
2089                            event.target.classList.add('pys-mouse-over-' + eventId);
2090                        }
2091
2092                        Utils.handleTriggerFired(eventId, triggerType || 'css_mouseover');
2093                    }
2094                });
2095
2096
2097            },
2098
2099            setupFormFieldEvents: function (eventId, triggers, triggerType) {
2100                triggers.forEach(function(trigger) {
2101                    let eventType = 'input';
2102
2103                    if (['checkbox', 'radio', 'select'].includes(trigger.type)) {
2104                        eventType = 'change';
2105                    } else if (['text', 'email', 'tel'].includes(trigger.type)) {
2106                        eventType = 'blur';
2107                    }
2108
2109                    const form = document.querySelector(trigger.form);
2110                    if (!form) return;
2111
2112                    const field = form.querySelector(trigger.field); // search for the field ONLY within the form
2113                    if (!field) return;
2114
2115                    field.addEventListener(eventType, function (event) {
2116                        Utils.handleTriggerFired(eventId, triggerType || 'form_field');
2117                    }, true);
2118                });
2119            },
2120
2121            setupCSSClickEvents: function (eventId, triggers, triggerType, clickCount, clickTimeLimit) {
2122                // Non-default binding used to avoid situations when some code in external js
2123                // stopping events propagation, eg. returns false, and our handler will never called
2124                // add event to document to support dyn class
2125                var requiredClicks = (clickCount && clickCount > 1) ? clickCount : 1;
2126                var timeWindow     = (clickTimeLimit && clickTimeLimit > 0) ? clickTimeLimit : 0;
2127                var clickCounters  = typeof WeakMap !== 'undefined' ? new WeakMap() : null;
2128
2129                document.addEventListener('click', function(event) {
2130                    let matchedElements = Array.from(document.querySelectorAll(triggers)),
2131                        clickedElement = event.target,
2132                        closestMatch = clickedElement.closest(triggers);
2133
2134                    if (matchedElements.includes(clickedElement) || closestMatch) {
2135                        var target = closestMatch || clickedElement;
2136
2137                        if (requiredClicks <= 1) {
2138                            Utils.handleTriggerFired(eventId, triggerType || 'css_click');
2139                            return;
2140                        }
2141
2142                        if (!clickCounters) {
2143                            Utils.handleTriggerFired(eventId, triggerType || 'css_click');
2144                            return;
2145                        }
2146
2147                        var now = Date.now();
2148                        var state = clickCounters.get(target) || { count: 0, last: 0, timer: null };
2149
2150                        // When a time window is set, reset the counter if the gap exceeded it.
2151                        if (timeWindow > 0 && now - state.last > timeWindow) {
2152                            state.count = 0;
2153                        }
2154                        state.count++;
2155                        state.last = now;
2156
2157                        if (state.timer) clearTimeout(state.timer);
2158                        // Schedule cleanup to avoid memory leaks.
2159                        // With time window: delete entry after window expires.
2160                        // Without: quietly clear the timer reference after a long idle period.
2161                        state.timer = setTimeout(function() {
2162                            if (clickCounters) {
2163                                if (timeWindow > 0) {
2164                                    clickCounters.delete(target);
2165                                } else {
2166                                    var s = clickCounters.get(target);
2167                                    if (s) { s.timer = null; clickCounters.set(target, s); }
2168                                }
2169                            }
2170                        }, timeWindow > 0 ? timeWindow : 60000);
2171
2172                        clickCounters.set(target, state);
2173
2174                        if (state.count >= requiredClicks) {
2175                            clickCounters.delete(target);
2176                            Utils.handleTriggerFired(eventId, triggerType || 'css_click');
2177                        }
2178                    }
2179                }, true);
2180            },
2181
2182            setupCopyElementEvents: function (eventId, selectors) {
2183                var selectorList = Array.isArray(selectors) ? selectors.join(',') : selectors;
2184                if (!selectorList) return;
2185
2186                document.addEventListener('copy', function() {
2187                    var selection = window.getSelection();
2188                    if (!selection || selection.isCollapsed) return;
2189
2190                    var node = selection.focusNode;
2191                    var el = node ? (node.nodeType === 3 ? node.parentElement : node) : null;
2192                    if (!el) return;
2193
2194                    try {
2195                        if (el.closest(selectorList)) {
2196                            Utils.handleTriggerFired(eventId, 'copy_element');
2197                        }
2198                    } catch (e) {}
2199                });
2200            },
2201
2202            setupVideoSpeedEvents: function (eventId, config) {
2203                var urls      = Array.isArray(config) ? config : (config.urls || []);
2204                var speedRate = Array.isArray(config) ? 'any' : (config.speed_rate || 'any');
2205                var triggers  = Array.isArray(config) ? [] : (config.triggers || []);
2206
2207                var matchesPage = function() {
2208                    if (!urls || urls.length === 0) return false;
2209                    var href = window.location.href;
2210                    return urls.some(function(u) {
2211                        return u === '*' || u === '' || href.indexOf(u) !== -1;
2212                    });
2213                };
2214
2215                var matchesRate = function(prev, curr) {
2216                    if (speedRate === 'any') return curr !== prev;
2217                    if (speedRate === 'increase') return curr > prev;
2218                    if (speedRate === 'decrease') return curr < prev;
2219                    return false;
2220                };
2221
2222
2223                var matchesVideoId = function(videoId) {
2224                    if (!triggers || triggers.length === 0) return true;
2225                    var decId;
2226                    try { decId = decodeURIComponent(videoId); } catch(e) { decId = videoId; }
2227                    return triggers.some(function(t) {
2228                        if (t.rule === videoId || t.rule === String(videoId)) return true;
2229                        var decRule;
2230                        try { decRule = decodeURIComponent(t.rule); } catch(e) { decRule = t.rule; }
2231                        return decRule === decId;
2232                    });
2233                };
2234
2235                if (!matchesPage()) return;
2236
2237                // HTML5 <video> speed tracking
2238                document.addEventListener('ratechange', function(event) {
2239                    var video = event.target;
2240                    if (!video || video.tagName !== 'VIDEO') return;
2241                    var prev = video._pysSpeedRate !== undefined ? video._pysSpeedRate : 1;
2242                    var curr = video.playbackRate;
2243                    video._pysSpeedRate = curr;
2244
2245                    if (matchesRate(prev, curr)) {
2246                        var videoId = video.id || video.src || video.currentSrc || '';
2247                        if (matchesVideoId(videoId)) {
2248                            Utils.handleTriggerFired(eventId, 'video_speed');
2249                        }
2250                    }
2251                }, true);
2252            },
2253
2254            setupURLClickEvents: function () {
2255
2256                if( !options.triggerEventTypes.hasOwnProperty('url_click') ) {
2257                    return;
2258                }
2259                // Non-default binding used to avoid situations when some code in external js
2260                // stopping events propagation, eg. returns false, and our handler will never called
2261                document.addEventListener('click', function(event) {
2262                    let anchor = event.target.closest('a');
2263
2264                    if (anchor) {
2265                        var url = anchor.getAttribute('href');
2266                        if (url) {
2267                            Object.entries(options.triggerEventTypes.url_click).forEac
2267h(function ([eventId, triggers]) {
2268                                triggers.forEach(function (trigger) {
2269                                    if (Utils.compareUrl(url, trigger.value, trigger.rule)) {
2270                                        Utils.handleTriggerFired(eventId, 'url_click');
2271                                    }
2272                                });
2273                            });
2274                        }
2275                    }
2276                }, true);
2277
2278            },
2279
2280            removeUrlDomain(url) {
2281                if(url.indexOf("/#") > -1) {
2282                    url = url.substring(0, url.indexOf("/#"));
2283                }
2284                return url.replace('http://','')
2285                    .replace('https://','')
2286                    .replace('www.','')
2287                    .trim()
2288                    .replace(/^\/+/g, '')
2289
2290            },
2291
2292            compareUrl: function(base,url,rule){
2293
2294                if(url == "*" || url == '') return true;
2295
2296                base = Utils.removeUrlDomain(base)
2297                url = Utils.removeUrlDomain(url)
2298
2299                if(rule == 'match') {
2300                    return url == base;
2301                } else {
2302                    return base.indexOf(url) !== -1
2303                }
2304
2305            },
2306
2307            setupScrollPosEvents: function (eventId, triggers, triggerType) {
2308
2309                var scrollPosThresholds = {},
2310                    docHeight = $(document).height() - $(window).height();
2311
2312                // convert % to absolute positions
2313                $.each(triggers, function (index, scrollPos) {
2314
2315                    // convert % to pixels
2316                    scrollPos = docHeight * scrollPos / 100;
2317                    scrollPos = Math.round(scrollPos);
2318
2319                    scrollPosThresholds[scrollPos] = eventId;
2320
2321                });
2322
2323                $(document).on("scroll",function () {
2324
2325                    var scrollPos = $(window).scrollTop();
2326
2327                    $.each(scrollPosThresholds, function (threshold, eventId) {
2328
2329                        // position has not reached yes
2330                        if (scrollPos < threshold - 0.5) {
2331                            return true;
2332                        }
2333
2334                        // fire event only once
2335                        if (eventId === null) {
2336                            return true;
2337                        } else {
2338                            scrollPosThresholds[threshold] = null;
2339                        }
2340
2341                        Utils.handleTriggerFired(eventId, triggerType || 'scroll_pos');
2342                    });
2343
2344                });
2345
2346            },
2347            setupCommentEvents : function (eventId,triggers) {
2348                $('form.comment-form').on("submit",function () {
2349                    Utils.fireTriggerEvent(eventId);
2350                });
2351            },
2352
2353            setupEmailLinkEvents: function ( events ) {
2354
2355                $( document ).on( 'click', 'a', function ( event ) {
2356                    let anchor = event.target.closest('a');
2357
2358                    if (anchor) {
2359                        let url = anchor.getAttribute('href');
2360                        if (url && (url.startsWith('mailto:') || url.startsWith('tel:'))) {
2361
2362                            let sendEventIds = [],
2363                                disabled_for_pixels = [],
2364                                disabled_email_action = false;
2365
2366                            $.each(events, function (eventId, trigger_group) {
2367                                url = url.replace('mailto:', '').replace('tel:', '');
2368                                trigger_group.forEach(function (triggers) {
2369                                    triggers.rules.forEach(function (trigger) {
2370                                        if (Utils.compareUrl(url, trigger.value, trigger.rule)) {
2371                                            sendEventIds.push(eventId);
2372                                            if (triggers.hasOwnProperty('disabled_email_link') && triggers.disabled_email_link) {
2373                                                disabled_email_action = true;
2374                                                if (options.triggerEvents.hasOwnProperty(eventId)) {
2375                                                    disabled_for_pixels.push(...Object.keys(options.triggerEvents[eventId]));
2376                                                }
2377                                            }
2378                                        }
2379                                    });
2380                                })
2381                            })
2382
2383                            if (sendEventIds.length > 0) {
2384                                sendEventIds.forEach(function (sendEventId) {
2385                                    Utils.handleTriggerFired(sendEventId, 'email_link');
2386                                })
2387                            }
2388                            setupEmailLinks(disabled_for_pixels);
2389                        }
2390                    }
2391                } )
2392            },
2393
2394            /**
2395             * Events
2396             */
2397
2398            isEventInTimeWindow: function (eventName, event, prefix) {
2399
2400                if(event.hasOwnProperty("hasTimeWindow") && event.hasTimeWindow) {
2401                    var cookieName = prefix+"_"+eventName;
2402                    var now = new Date().getTime();
2403
2404                    if(Cookies.get(cookieName) !== undefined) {
2405
2406                        var lastTimeFire = Cookies.get(cookieName);
2407                        var fireTime = event.timeWindow * 60*60*1000;
2408
2409                        if( now - lastTimeFire > fireTime) {
2410                            Cookies.set(cookieName,now, { expires: event.timeWindow / 24.0, path: '/'} );
2411                        } else {
2412                            return false;
2413                        }
2414                    } else {
2415                        Cookies.set(cookieName,now, { expires: event.timeWindow / 24.0, path: '/'} );
2416                    }
2417                }
2418                return true
2419            },
2420
2421            handleTriggerFired: function (eventId, triggerType) {
2422                if (options.triggerLogic && options.triggerLogic[eventId] === 'AND') {
2423                    var state = pysCustomEventsState[eventId];
2424                    if (!state || state.fired) return;
2425                    state.triggered[triggerType] = true;
2426                    if (Object.keys(state.triggered).length >= state.total) {
2427                        state.fired = true;
2428                        Utils.fireTriggerEvent(eventId);
2429                    }
2430                } else {
2431                    Utils.fireTriggerEvent(eventId);
2432                }
2433            },
2434
2435            fireTriggerEvent: function (eventId) {
2436
2437                if (!options.triggerEvents.hasOwnProperty(eventId)) {
2438                    return;
2439                }
2440
2441                if (options.triggerFrequency && options.triggerFrequency[eventId] === 'once') {
2442                    if (pysEventFiredOnce[eventId]) return;
2443                    pysEventFiredOnce[eventId] = true;
2444                }
2445
2446                var event = {};
2447                var events = options.triggerEvents[eventId];
2448
2449                if (events.hasOwnProperty('facebook')) {
2450                    event = events.facebook;
2451                    if(Utils.isEventInTimeWindow(event.name,event,"dyn_facebook_"+eventId)) {
2452                        event = Utils.getFormFilledData(event);
2453                        Facebook.fireEvent(event.name, event);
2454                    }
2455                }
2456
2457                if (events.hasOwnProperty('ga')) {
2458                    event = events.ga;
2459                    if(Utils.isEventInTimeWindow(event.name,event,"dyn_ga_"+eventId)) {
2460                        event = Utils.getFormFilledData(event);
2461                        Analytics.fireEvent(event.name, event);
2462                    }
2463                }
2464
2465                if (events.hasOwnProperty('google_ads')) {
2466                    event = events.google_ads;
2467                    if(Utils.isEventInTimeWindow(event.name,event,"dyn_google_ads_"+eventId)) {
2468                        event = Utils.getFormFilledData(event);
2469                        GAds.fireEvent(event.name, event);
2470                    }
2471                }
2472
2473                if (events.hasOwnProperty('pinterest')) {
2474                    event = events.pinterest;
2475                    if(Utils.isEventInTimeWindow(event.name,event,"dyn_pinterest_"+eventId)) {
2476                        event = Utils.getFormFilledData(event);
2477                        Pinterest.fireEvent(event.name, event);;
2478                    }
2479                }
2480
2481                if (events.hasOwnProperty('bing')) {
2482                    event = events.bing;
2483                    if(Utils.isEventInTimeWindow(event.name,event,"dyn_bing_"+eventId)) {
2484                        event = Utils.getFormFilledData(event);
2485                        Bing.fireEvent(event.name, event);;
2486                    }
2487                }
2488                if (events.hasOwnProperty('tiktok')) {
2489                    event = events.tiktok;
2490                    if(Utils.isEventInTimeWindow(event.name,event,"dyn_tiktok_"+eventId)) {
2491                        event = Utils.getFormFilledData(event);
2492                        TikTok.fireEvent(event.name, event);
2493                    }
2494                }
2495	            if (events.hasOwnProperty('reddit')) {
2496		            event = events.reddit;
2497		            if(Utils.isEventInTimeWindow(event.name,event,"dyn_reddit_"+eventId)) {
2498			            event = Utils.getFormFilledData(event);
2499			            Reddit.fireEvent(event.name, event);
2500		            }
2501	            }
2502
2503
2504                if (events.hasOwnProperty('gtm')) {
2505                    event = events.gtm;
2506                    if(Utils.isEventInTimeWindow(event.name,event,"dyn_gtm_"+eventId)) {
2507                        event = Utils.getFormFilledData(event);
2508                        GTM.fireEvent(event.name, event);
2509                    }
2510                }
2511
2512
2513            },
2514
2515            isFirstPurchaseFire: function ($eventName,orderId,pixel) {
2516
2517                if(Cookies.get("pys_"+$eventName+"_order_id_"+pixel) == orderId) {
2518                    return false;
2519                } else {
2520                    Cookies.set("pys_"+$eventName+"_order_id_"+pixel, orderId, { expires: 1,path: '/' });
2521                }
2522                return true;
2523            },
2524
2525            fireStaticEvents: function (pixel, timeout = 0) {
2526
2527                if (options.staticEvents.hasOwnProperty(pixel)) {
2528
2529                    $.each(options.staticEvents[pixel], function (eventId, events) {
2530
2531                        //skip purchase event if this order was fired
2532                        if( options.woo.hasOwnProperty('woo_purchase_on_transaction') &&
2533                            options.woo.woo_purchase_on_transaction &&
2534                            (eventId === "woo_purchase" || eventId === "woo_purchase_category") ) {
2535                            if(!Utils.isFirstPurchaseFire(eventId,events[0].woo_order,pixel)) {
2536                                return;
2537                            }
2538                        }
2539
2540                        if( options.edd.hasOwnProperty('edd_purchase_on_transaction') &&
2541                            options.edd.edd_purchase_on_transaction &&
2542                            (eventId === "edd_purchase" || eventId === "edd_purchase_category") ) {
2543                            if(!Utils.isFirstPurchaseFire(eventId,events[0].edd_order,pixel)) {
2544                                return;
2545                            }
2546                        }
2547
2548
2549                        $.each(events, function (index, event) {
2550
2551                            event.fired = event.fired || false;
2552
2553                            if (!event.fired && Utils.isEventInTimeWindow(event.
2553name,event,'static_' + pixel+"_")) {
2554                                event = Utils.getFormFilledData(event);
2555
2556                                var fired = false;
2557
2558                                // fire event
2559                                if ( pixel === 'tiktok' ) {
2560                                    setTimeout(function() {
2561                                        getPixelBySlag(pixel).fireEvent(event.name, event);
2562                                    }, timeout * 500);
2563                                    timeout++;
2564                                } else {
2565                                    getPixelBySlag(pixel).fireEvent(event.name, event);
2566                                }
2567
2568                                // prevent event double event firing
2569                                event.fired = fired;
2570                            }
2571                        });
2572                    });
2573                }
2574            },
2575
2576            /**
2577             * Load tag's JS
2578             *
2579             * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/
2580             * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/custom-dims-mets
2581             */
2582            loadGoogleTag: function (id) {
2583
2584                if (!gtag_loaded) {
2585                    let dataLayerName = this.dataLayerName;
2586                    if(options.hasOwnProperty('GATags')){
2587                        switch (options.GATags.ga_datalayer_type) {
2588                            case 'default':
2589                                dataLayerName = 'dataLayerPYS';
2590                                break;
2591                            case 'custom':
2592                                dataLayerName = options.GATags.ga_datalayer_name;
2593                                break;
2594                            default:
2595                                dataLayerName = 'dataLayer';
2596                        }
2597                    }
2598                    this.dataLayerName = dataLayerName;
2599                    (function (window, document, src) {
2600                        var a = document.createElement('script'),
2601                            m = document.getElementsByTagName('script')[0];
2602                        a.async = 1;
2603                        a.src = src;
2604                        m.parentNode.insertBefore(a, m);
2605                    })(window, document, '//www.googletagmanager.com/gtag/js?id=' + id+'&l='+this.dataLayerName);
2606
2607                    window[dataLayerName] = window[dataLayerName] || [];
2608                    window.gtag = window.gtag || function gtag() {
2609                        window[dataLayerName].push(arguments);
2610                    };
2611
2612                    if ( options.google_consent_mode ) {
2613                        let data = {};
2614                        data[ 'analytics_storage' ] = options.gdpr.analytics_storage.enabled ? options.gdpr.analytics_storage.value : 'granted';
2615                        data[ 'ad_storage' ] = options.gdpr.ad_storage.enabled ? options.gdpr.ad_storage.value : 'granted';
2616                        data[ 'ad_user_data' ] = options.gdpr.ad_user_data.enabled ? options.gdpr.ad_user_data.value : 'granted';
2617                        data[ 'ad_personalization' ] = options.gdpr.ad_personalization.enabled ? options.gdpr.ad_personalization.value : 'granted';
2618
2619                        this.loadDefaultConsent( 'consent', 'default', data );
2620                    }
2621
2622                    gtag('js', new Date());
2623                    gtag_loaded = true;
2624
2625                }
2626
2627            },
2628
2629            loadDefaultConsent: function() {
2630                window[ this.dataLayerName ].push( arguments );
2631            },
2632
2633            loadGTMScript: function (id = '') {
2634                // Strip trailing slash to allow both "domain.com" and "domain.com/" inputs.
2635                const domain = ( options.gtm.gtm_container_domain ?? 'www.googletagmanager.com' ).replace( /\/$/, '' );
2636                const loader = options.gtm.gtm_container_identifier ?? 'gtm';
2637                const gtm_auth = options.gtm.gtm_auth ?? '';
2638                const gtm_preview = options.gtm.gtm_preview ?? '';
2639                const datalayer_name = options.gtm.gtm_dataLayer_name ?? 'dataLayer';
2640
2641                window[ datalayer_name ] = window[ datalayer_name ] || [];
2642                window.gtag = window.gtag || function gtag() {
2643                    window[ datalayer_name ].push( arguments );
2644                };
2645
2646                // Push consent defaults synchronously before the GTM script tag is inserted.
2647                // When PYS loads the GTM snippet itself (non-dataLayer-only mode), this ensures
2648                // defaults are in the dataLayer before GTM processes any events.
2649                this.pushGTMConsentDefaults( datalayer_name );
2650
2651                (function(w, d, s, l, i) {
2652                    w[l] = w[l] || [];
2653                    w[l].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' });
2654                    const f = d.getElementsByTagName(s)[0];
2655                    const j = d.createElement(s);
2656                    const dl = l !== 'dataLayer' ? '&l=' + l : '';
2657                    j.async = true;
2658
2659                    // Detect domain format: bare hostname (legacy) vs full URL / relative path (new).
2660                    // Legacy "www.googletagmanager.com" → prepe
2660nd https:// and append .js.
2661                    // New format "/metrics" or "https://custom.com" → use as-is.
2662                    //   Identifier with extension (e.g. "gtm.js")  → file:   domain/gtm.js?id=
2663                    //   Identifier without extension (e.g. "g4h25o") → path: domain/g4h25o/?id=
2664                    const isNewFormat = domain.startsWith( 'http://' )
2665                                     || domain.startsWith( 'https://' )
2666                                     || domain.startsWith( '/' );
2667
2668                    if ( !isNewFormat ) {
2669                        j.src = 'https://' + domain + '/' + loader + '.js?id=' + i + dl;
2670                    } else {
2671                        const hasExtension = loader.includes( '.' );
2672                        j.src = domain + '/' + loader + ( hasExtension ? '?' : '/?' ) + 'id=' + i + dl;
2673                    }
2674
2675                    if (gtm_auth && gtm_preview) {
2676                        j.src += '&gtm_auth=' + gtm_auth + '&gtm_preview=' + gtm_preview + '&gtm_cookies_win=x';
2677                    }
2678                    f.parentNode.insertBefore(j, f);
2679                })(window, document, 'script', datalayer_name, id);
2680
2681            },
2682
2683            loadDefaultGTMConsent: function() {
2684                window[ this.GTMdataLayerName ].push( arguments );
2685            },
2686
2687            // Extracted helper: push GTM consent defaults to the dataLayer.
2688            // Called from loadGTMScript (when PYS loads the snippet) and from
2689            // GTM.loadPixel when gtm_just_data_layer is enabled, so defaults are
2690            // always present regardless of which code path loads the GTM container.
2691            pushGTMConsentDefaults: function( datalayer_name ) {
2692                if ( !options.google_consent_mode ) {
2693                    return;
2694                }
2695                let data = {};
2696                data[ 'analytics_storage' ]  = options.gdpr.analytics_storage.enabled  ? options.gdpr.analytics_storage.value  : 'granted';
2697                data[ 'ad_storage' ]         = options.gdpr.ad_storage.enabled         ? options.gdpr.ad_storage.value         : 'granted';
2698                data[ 'ad_user_data' ]       = options.gdpr.ad_user_data.enabled       ? options.gdpr.ad_user_data.value       : 'granted';
2699                data[ 'ad_personalization' ] = options.gdpr.ad_personalization.enabled ? options.gdpr.ad_personalization.value : 'granted';
2700                this.GTMdataLayerName = datalayer_name;
2701                this.loadDefaultGTMConsent( 'consent', 'default', data );
2702            },
2703
2704            /**
2705             * GDPR
2706             */
2707
2708            loadPixels: function () {
2709
2710                if (options.gdpr.ajax_enabled && !options.gdpr.consent_magic_integration_enabled) {
2711
2712                    // retrieves actual PYS GDPR filters values which allow to avoid cache issues
2713                    $.get({
2714                        url: options.ajaxUrl,
2715                        dataType: 'json',
2716                        data: {
2717                            action: 'pys_get_gdpr_filters_values'
2718                        },
2719                        success: function (res) {
2720
2721                            if (res.success) {
2722
2723                                options.gdpr.all_disabled_by_api = res.data.all_disabled_by_api;
2724                                options.gdpr.facebook_disabled_by_api = res.data.facebook_disabled_by_api;
2725                                options.gdpr.tiktok_disabled_by_api = res.data.tiktok_disabled_by_api;
2726                                options.gdpr.analytics_disabled_by_api = res.data.analytics_disabled_by_api;
2727                                options.gdpr.google_ads_disabled_by_api = res.data.google_ads_disabled_by_api;
2728                                options.gdpr.pinterest_disabled_by_api = res.data.pinterest_disabled_by_api;
2729                                options.gdpr.bing_disabled_by_api = res.data.bing_disabled_by_api;
2730                                options.gdpr.reddit_disabled_by_api = res.data.reddit_disabled_by_api;
2731
2732                                options.cookie.externalID_disabled_by_api = res.data.externalID_disabled_by_api;
2733                                options.cookie.disabled_all_cookie = res.data.disabled_all_cookie;
2734                                options.cookie.disabled_advanced_form_data_cookie = res.data.disabled_advanced_form_data_cookie;
2735                                options.cookie.disabled_landing_page_cookie = res.data.disabled_landing_page_cookie || !options.enable_lading_page_param;
2736                                options.cookie.disabled_first_visit_cookie = res.data.disabled_first_visit_cookie;
2737                                options.cookie.disabled_trafficsource_cookie = res.data.disabled_trafficsource_cookie;
2738                                options.cookie.disabled_utmTerms_cookie = res.data.disabled_utmTerms_cookie;
2739                                options.cookie.disabled_utmId_cookie = res.data.disabled_utmId_cookie;
2740                            }
2741                            loadPixels();
2742
2743                        }
2744                    });
2745
2746                } else {
2747                    loadPixels();
2748                }
2749
2750            },
2751
2752            consentGiven: function (pixel) {
2753
2754                /**
2755                 * Cookiebot
2756                 */
2757                if (options.gdpr.cookiebot_integration_enabled && typeof Cookiebot !== 'undefined') {
2758
2759                    var cookiebot_consent_category = options.gdpr['cookiebot_' + pixel + '_consent_category'];
2760
2761                    if (options.gdpr[pixel + '_prior_consent_enabled']) {
2762                        if (Cookiebot.consented === true || Cookiebot.consent[cookiebot_consent_category]) {
2763                            return true;
2764                        }
2765                    } else {
2766                        if (Cookiebot.consent[cookiebot_consent_category]) {
2767                            return true;
2768                        }
2769                    }
2770                    return false;
2771
2772                }
2773
2774                /**
2775                 * Cookie Notice
2776                 */
2777                if (options.gdpr.cookie_notice_integration_enabled && typeof cnArgs !== 'undefined') {
2778
2779                    var cn_cookie = Cookies.get(cnArgs.cookieName);
2780
2781                    if (options.gdpr[pixel + '_prior_consent_enabled']) {
2782                        if (typeof cn_cookie === 'undefined' || cn_cookie === 'true') {
2783                            return true;
2784                        }
2785                    } else {
2786                        if (cn_cookie === 'true') {
2787                            return true;
2788                        }
2789                    }
2790
2791                    return false;
2792
2793                }
2794
2795                /**
2796                 * Cookie Law Info
2797                 */
2798
2799                if (options.gdpr.cookie_law_info_integration_enabled) {
2800                    var cli_cookie = Cookies.get('cookieyes-consent') ?? Cookies.get('wt_consent') ?? Cookies.get('viewed_cookie_policy');
2801                    if (options.gdpr[pixel + '_prior_consent_enabled']) {
2802                        if (typeof cli_cookie === 'undefined') return true;
2803                        if (
2804                            cli_cookie &&
2805                            (cli_cookie === Cookies.get('cookieyes-consent') || cli_cookie === Cookies.get('wt_consent'))
2806                        ) {
2807                            if (getCookieYes('analytics') === 'yes') {
2808                                return true;
2809                            }
2810                        } else if (cli_cookie && cli_cookie === Cookies.get('viewed_cookie_policy')) {
2811                            if (Cookies.get('viewed_cookie_policy') === 'yes') {
2812                                return true;
2813                            }
2814                        }
2815                    } else {
2816                        if (
2817                            cli_cookie &&
2818                            (cli_cookie === Cookies.get('cookieyes-consent') || cli_cookie === Cookies.get('wt_consent'))
2819                        ) {
2820                            if (getCookieYes('analytics') === 'yes') {
2821                                return true;
2822                            }
2823                        } else if (cli_cookie && cli_cookie === Cookies.get('viewed_cookie_policy')) {
2824                            if (Cookies.get('viewed_cookie_policy') === 'yes') {
2825                                return true;
2826                            }
2827                        }
2828                    }
2829                    return false;
2830                }
2831
2832                /**
2833                 * ConsentMagic
2834                 */
2835                if (options.gdpr.consent_magic_integration_enabled && typeof CS_Data !== "undefined" ) {
2836
2837                    let test_prefix = CS_Data.test_prefix;
2838                    if (
2839                        ( ( typeof CS_Data.cs_google_consent_mode_enabled !== "undefined" && CS_Data.cs_google_consent_mode_enabled == 1 ) && ( pixel == 'analytics' || pixel == 'google_ads' ) )
2840                        || ( typeof CS_Data.cs_meta_ldu_mode !== "undefined" && CS_Data.cs_meta_ldu_mode && pixel == 'facebook' )
2841                        || ( typeof CS_Data.cs_reddit_ldu_mode !== "undefined" && CS_Data.cs_reddit_ldu_mode && pixel == 'reddit' )
2842                        || ( typeof CS_Data.cs_bing_consent_mode !== "undefined" && CS_Data.cs_bing_consent_mode.ad_storage.enabled && pixel == 'bing' )
2843                    ) {
2844                        if ( CS_Data.cs_cache_enabled == 0 || ( CS_Data.cs_cache_enabled == 1 && window.CS_Cache && window.CS_Cache.check_status ) ) {
2845                            return true;
2846                        } else {
2847                            return false;
2848                        }
2849                    }
2850
2851                    if( pixel == 'facebook' && ( CS_Data.cs_script_cat.facebook == 0 || CS_Data.cs_script_cat.facebook == CS_Data.cs_necessary_cat_id ) ) {
2852                        return true;
2853                    } else if( pixel == 'bing' && ( CS_Data.cs_script_cat.bing == 0 || CS_Data.cs_script_cat.bing == CS_Data.cs_necessary_cat_id ) ) {
2854                        return true;
2855                    } else if( pixel == 'analytics' && ( CS_Data.cs_script_cat.analytics == 0 || CS_Data.cs_script_cat.analytics == CS_Data.cs_necessary_cat_id ) ) {
2856                        return true;
2857                    } else if( pixel == 'google_ads' && ( CS_Data.cs_script_cat.gads == 0 || CS_Data.cs_script_cat.gads == CS_Data.cs_necessary_cat_id ) ) {
2858                        return true;
2859                    } else if( pixel == 'pinterest' && ( CS_Data.cs_script_cat.pinterest == 0 || CS_Data.cs_script_cat.pinterest == CS_Data.cs_necessary_cat_id ) ) {
2860                        return true;
2861                    } else if( pixel == 'tiktok' && ( CS_Data.cs_script_cat.tiktok == 0 || CS_Data.cs_script_cat.tiktok == CS_Data.cs_necessary_cat_id ) ) {
2862                        return true;
2863                    } else if( pixel == 'reddit' && ( CS_Data.cs_script_cat?.reddit == 0 || CS_Data.cs_script_cat?.reddit == CS_Data.cs_necessary_cat_id ) ) {
2864		                return true;
2865	                }
2866
2867                    let substring = "cs_enabled_cookie_term",
2868                        theCookies = document.cookie.split( ';' );
2869
2870                    for ( let i = 1; i <= theCookies.length; i++ ) {
2871                        if ( theCookies[ i - 1 ].indexOf( substring ) !== -1 ) {
2872                            let categoryCookie = theCookies[ i - 1 ].replace( 'cs_enabled_cookie_term' + test_prefix + '_', '' );
2873                            categoryCookie = Number( categoryCookie.replace( /\D+/g, "" ) );
2874                            let cs_cookie_val = Cookies.get( 'cs_enabled_cookie_term' + test_prefix + '_' + categoryCookie );
2875
2876                            if ( categoryCookie === CS_Data.cs_script_cat.facebook && pixel == 'facebook' ) {
2877                                return cs_cookie_val == 'yes';
2878                            } else if ( categoryCookie === CS_Data.cs_script_cat.bing && pixel == 'bing' ) {
2879                                return cs_cookie_val == 'yes';
2880                            } else if ( categoryCookie === CS_Data.cs_script_cat.analytics && pixel == 'analytics' ) {
2881                                return cs_cookie_val == 'yes';
2882                            } else if ( categoryCookie === CS_Data.cs_script_cat.gads && pixel == 'google_ads' ) {
2883                                return cs_cookie_val == 'yes';
2884                            } else if ( categoryCookie === CS_Data.cs_script_cat.pinterest && pixel == 'pinterest' ) {
2885                                return cs_cookie_val == 'yes';
2886                            } else if ( categoryCookie === CS_Data.cs_script_cat.tiktok && pixel == 'tiktok' ) {
2887                                return cs_cookie_val == 'yes';
2888                            } else if ( categoryCookie === CS_Data.cs_script_cat?.reddit && pixel == 'reddit' ) {
2889	                            return cs_cookie_val == 'yes';
2890                            }
2891                        }
2892                    }
2893
2894                    return false;
2895                }
2896
2897
2898                /**
2899                 * Real Cookie Banner
2900                 */
2901                if (options.gdpr.real_cookie_banner_integration_enabled) {
2902                    var consentApi = window.consentApi;
2903                    if (consentApi) {
2904                        switch (pixel) {
2905                            case "analytics":
2906                                return consentApi.consentSync("http", "_ga", "*").cookieOptIn;
2907                            case "facebook":
2908                                return consentApi.consentSync("http", "_fbp", "*").cookieOptIn;
2909                            case "pinterest":
2910                                return consentApi.consentSync("http", "_pinterest_sess", ".pinterest.com").cookieOptIn;
2911                            case "bing":
2912                                return consentApi.consentSync("http", "_uetsid", "*").cookieOptIn;
2913                            case "google_ads":
2914                                return consentApi.consentSync("http", "1P_JAR", ".google.com").cookieOptIn;
2915                            case 'tiktok':
2916                                return consentApi.consentSync("http", "tt_webid_v2", ".tiktok.com").cookieOptIn;
2917                            default:
2918                                return true;
2919                        }
2920                    }
2921                }
2922
2923                return true;
2924
2925            },
2926
2927            setupGdprCallbacks: function () {
2928
2929                let isConcent = false;
2930
2931                /**
2932                 * Cookiebot
2933                 */
2934                if ( options.gdpr.cookiebot_integration_enabled && typeof Cookiebot !== 'undefined' ) {
2935                    isConcent = true;
2936                    window.addEventListener( "CookiebotOnConsentReady", function () {
2937
2938                        let consent = {
2939                            facebook: true,
2940                            ga: true,
2941                            google_ads: true,
2942                            tiktok: true,
2943                            bing: true,
2944                            pinterest: true,
2945                            gtm: true,
2946                        };
2947                        Utils.initializeVideoAPIs( options );
2948
2949                        Utils.manageCookies();
2950                        if ( Cookiebot.consent.marketing ) {
2951                            Facebook.loadPixel();
2952                            Bing.loadPixel();
2953                            Pinterest.loadPixel();
2954                            GAds.loadPixel();
2955                            TikTok.loadPixel();
2956
2957                            consent.facebook = true;
2958                            consent.bing = true;
2959                            consent.google_ads = true;
2960                            consent.pinterest = true;
2961                            consent.tiktok = true;
2962                        }
2963                        if ( Cookiebot.consent.statistics ) {
2964                            Analyti
2964cs.loadPixel();
2965
2966                            consent.ga = true;
2967                            consent.gtm = true;
2968                        }
2969                        if ( !Cookiebot.consent.marketing ) {
2970                            Facebook.disable();
2971                            Pinterest.disable();
2972                            Bing.disable()
2973                            GAds.disable();
2974                            TikTok.disable();
2975
2976                            consent.facebook = false;
2977                            consent.bing = false;
2978                            consent.google_ads = false;
2979                            consent.pinterest = false;
2980                            consent.tiktok = false;
2981                        }
2982                        if ( !Cookiebot.consent.statistics ) {
2983                            Analytics.disable();
2984
2985                            consent.ga = false;
2986                            consent.gtm = false;
2987                        }
2988
2989                        Utils.setupGDPRData( consent );
2990                    } );
2991                }
2992
2993                /**
2994                 * Cookie Notice
2995                 */
2996                if ( options.gdpr.cookie_notice_integration_enabled ) {
2997                    isConcent = true;
2998                    $( document ).onFirst( 'click', '.cn-set-cookie', function () {
2999
3000                        let consent = {};
3001
3002                        if ( $( this ).data( 'cookie-set' ) === 'accept' ) {
3003
3004                            Utils.initializeVideoAPIs( options );
3005
3006                            Facebook.loadPixel();
3007                            Analytics.loadPixel();
3008                            GAds.loadPixel();
3009                            Pinterest.loadPixel();
3010                            Bing.loadPixel();
3011                            TikTok.loadPixel();
3012
3013                            consent = {
3014                                facebook: true,
3015                                ga: true,
3016                                google_ads: true,
3017                                tiktok: true,
3018                                bing: true,
3019                                pinterest: true,
3020                                gtm: true,
3021                            };
3022                        } else {
3023                            Facebook.disable();
3024                            Analytics.disable();
3025                            GAds.disable();
3026                            Pinterest.disable();
3027                            Bing.disable();
3028                            TikTok.disable();
3029
3030                            consent = {
3031                                facebook: false,
3032                                ga: false,
3033                                google_ads: false,
3034                                tiktok: false,
3035                                bing: false,
3036                                pinterest: false,
3037                                gtm: false,
3038                            };
3039                        }
3040                        Utils.setupGDPRData( consent );
3041
3042                    } );
3043
3044                    $( document ).onFirst( 'click', '.cn-revoke-cookie', function () {
3045                        Facebook.disable();
3046                        Analytics.disable();
3047                        GAds.disable();
3048                        Pinterest.disable();
3049                        Bing.disable();
3050                        TikTok.disable();
3051
3052                        let consent = {
3053                            facebook: false,
3054                            ga: false,
3055                            google_ads: false,
3056                            tiktok: false,
3057                            bing: false,
3058                            pinterest: false,
3059                            gtm: false,
3060                        };
3061                        Utils.setupGDPRData( consent );
3062
3063                    } );
3064                }
3065
3066                /**
3067                 * Cookie Law Info
3068                 */
3069                if ( options.gdpr.cookie_law_info_integration_enabled ) {
3070                    isConcent = true;
3071                    $( document ).onFirst( 'click', '#wt-cli-accept-all-btn,#cookie_action_close_header, .cky-btn-accept', function () {
3072                        Utils.initializeVideoAPIs( options );
3073                        setTimeout( function () {
3074                            let cli_cookie = Cookies.get( 'cookieyes-consent' ) ?? Cookies.get( 'wt_consent' ) ?? Cookies.get( 'viewed_cookie_policy' );
3075                            if ( typeof cli_cookie !== 'undefined' ) {
3076                                if (
3077                                    cli_cookie &&
3078                                    (cli_cookie === Cookies.get('cookieyes-consent') || cli_cookie === Cookies.get('wt_consent'))
3079                                ) {
3080                                    if (getCookieYes('analytics') === 'yes') {
3081                                        Utils.manageCookies();
3082                                    }
3083                                }
3083 else if ( cli_cookie === Cookies.get( 'viewed_cookie_policy' ) && cli_cookie == 'yes' ) {
3084                                    Utils.manageCookies();
3085                                }
3086                            }
3087                        }, 1000 )
3088                        Facebook.loadPixel();
3089                        Analytics.loadPixel();
3090                        GAds.loadPixel();
3091                        Pinterest.loadPixel();
3092                        Bing.loadPixel();
3093                        TikTok.loadPixel();
3094
3095                        let consent = {
3096                            facebook: true,
3097                            ga: true,
3098                            google_ads: true,
3099                            tiktok: true,
3100                            bing: true,
3101                            pinterest: true,
3102                            gtm: true,
3103                        };
3104                        Utils.setupGDPRData( consent );
3105                    } );
3106
3107                    $( document ).onFirst( 'click', '#cookie_action_close_header_reject, .cky-btn-reject', function () {
3108                        Facebook.disable();
3109                        Analytics.disable();
3110                        GAds.disable();
3111                        Pinterest.disable();
3112                        Bing.disable();
3113                        TikTok.disable();
3114
3115                        let consent = {
3116                            facebook: false,
3117                            ga: false,
3118                            google_ads: false,
3119                            tiktok: false,
3120                            bing: false,
3121                            pinterest: false,
3122                            gtm: false,
3123                        };
3124                        Utils.setupGDPRData( consent );
3125                    } );
3126                }
3127
3128                /**
3129                 * ConsentMagic
3130                 */
3131                if ( options.gdpr.consent_magic_integration_enabled && typeof CS_Data !== "undefined" ) {
3132                    isConcent = true;
3133                    let test_prefix = CS_Data.test_prefix,
3134                        cs_refresh_after_consent = false,
3135                        substring = "cs_enabled_cookie_term";
3136
3137                    if ( CS_Data.cs_refresh_after_consent == 1 ) {
3138                        cs_refresh_after_consent = CS_Data.cs_refresh_after_consent;
3139                    }
3140
3141                    let consent_actions = function () {
3142                        let theCookies = document.cookie.split( ';' );
3143
3144                        let consent = {
3145                            facebook: true,
3146                            ga: true,
3147                            google_ads: true,
3148                            tiktok: true,
3149                            bing: true,
3150                            pinterest: true,
3151                            gtm: true,
3152	                        reddit: true,
3153                        };
3154
3155                        for ( let i = 1; i <= theCookies.length; i++ ) {
3156                            if ( theCookies[ i - 1 ].indexOf( substring ) !== -1 ) {
3157                                let categoryCookie = theCookies[ i - 1 ].replace( 'cs_enabled_cookie_term' + test_prefix + '_', '' );
3158                                categoryCookie = Number( categoryCookie.replace( /\D+/g, "" ) );
3159                                let cs_cookie_val = Cookies.get( 'cs_enabled_cookie_term' + test_prefix + '_' + categoryCookie );
3160                                if ( cs_cookie_val == 'yes' ) {
3161
3162                                    Utils.initializeVideoAPIs( options );
3163
3164                                    if ( ( categoryCookie === CS_Data.cs_script_cat.facebook ) || ( typeof CS_Data.cs_meta_ldu_mode !== "undefined" && CS_Data.cs_meta_ldu_mode ) ) {
3165                                        Facebook.loadPixel();
3166                                    }
3167
3168                                    if ( categoryCookie === CS_Data.cs_script_cat.bing || ( typeof CS_Data.cs_bing_consent_mode !== "undefined" && CS_Data.cs_bing_consent_mode.ad_storage.enabled ) ) {
3169                                        Bing.loadPixel();
3170                                    }
3171
3172                                    if ( categoryCookie === CS_Data.cs_script_cat.analytics || ( typeof CS_Data.cs_google_analytics_consent_mode !== "undefined" && CS_Data.cs_google_analytics_consent_mode == 1 ) ) {
3173                                        Analytics.loadPixel();
3174                                    }
3175                                    if ( categoryCookie === CS_Data.cs_script_cat.gads || ( typeof CS_Data.cs_google_ads_consent_mode !== "undefined" && CS_Data.cs_google_ads_consent_mode == 1 ) ) {
3176                                        GAds.loadPixel();
3177                                    }
3178
3179                                    if ( categoryCookie === CS_Data.cs_script_cat.pinterest ) {
3180                                        Pinterest.loadPixel();
3181                                    }
3182
3183                                    if ( categoryCookie === CS_Data.cs_script_cat.tiktok ) {
3184                                        TikTok.loadPixel();
3185                                    }
3186
3187	                                if ( ( categoryCookie === CS_Data.cs_script_cat.reddit ) || ( typeof CS_Data.cs_reddit_ldu_mode !== "undefined" && CS_Data.cs_reddit_ldu_mode ) ) {
3188		                                Reddit.loadPixel();
3189	                                }
3190                                } else {
3191                                    if ( ( categoryCookie === CS_Data.cs_script_cat.facebook ) && ( typeof CS_Data.cs_meta_ldu_mode == "undefined" || !CS_Data.cs_meta_ldu_mode ) ) {
3192                                        Facebook.disable();
3193                                        consent.facebook = false;
3194                                    }
3195
3196                                    if ( categoryCookie === CS_Data.cs_script_cat.bing && ( typeof CS_Data.cs_bing_consent_mode == "undefined" || !CS_Data.cs_bing_consent_mode.ad_storage.enabled ) ) {
3197                                        Bing.disable();
3198                                        consent.bing = false;
3199                                    }
3200
3201                                    if ( categoryCookie === CS_Data.cs_script_cat.analytics && ( typeof CS_Data.cs_google_analytics_consent_mode == "undefined" || CS_Data.cs_google_analytics_consent_mode == 0 ) ) {
3202                                        Analytics.disable();
3203                                        consent.ga = false;
3204                                        consent.gtm = false;
3205                                    }
3206
3207                                    if ( categoryCookie === CS_Data.cs_script_cat.gads && ( typeof CS_Data.cs_google_ads_consent_mode == "undefined" || CS_Data.cs_google_ads_consent_mode == 0 ) ) {
3208                                        GAds.disable();
3209                                        consent.google_ads = false;
3210                                    }
3211
3212                                    if ( categoryCookie === CS_Data.cs_script_cat.pinterest ) {
3213                                        Pinterest.disable();
3214                                        consent.pinterest = false;
3215                                    }
3216
3217                                    if ( categoryCookie === CS_Data.cs_script_cat.tiktok ) {
3218                                        TikTok.disable();
3219                                        consent.tiktok = false;
3220                                    }
3221
3222	                                if ( ( categoryCookie === CS_Data.cs_script_cat.reddit ) && ( typeof CS_Data.cs_reddit_ldu_mode == "undefined" || !CS_Data.cs_reddit_ldu_mode ) ) {
3223		                                Reddit.disable();
3224		                                consent.reddit = false;
3225	                                }
3226                                }
3227                                if ( Cookies.get( 'cs_enabled_advanced_matching' ) == 'yes' ) {
3228                                    Facebook.loadPixel();
3229                                }
3230                            }
3231                        }
3232
3233                        Utils.setupGDPRData( consent );
3234                    }
3235
3236                    if ( !cs_refresh_after_consent ) {
3237                        consent_actions();
3238
3239                        $( document ).on( 'click', '.cs_action_btn', function ( e ) {
3240                            e.preventDefault();
3241
3242                            let consent = {
3243                                facebook: true,
3244                                ga: true,
3245                                google_ads: true,
3246                                tiktok: true,
3247                                bing: true,
3248                                pinterest: true,
3249                                gtm: true,
3250	                            reddit: true,
3251                            };
3252
3253                            let elm = $( this ),
3254                                button_action = elm.attr( 'data-cs_action' );
3255
3256                            if ( button_action === 'allow_all' ) {
3257
3258                                Utils.initializeVideoAPIs( options );
3259
3260                                Facebook.loadPixel();
3261                                Bing.loadPixel();
3262                                Analytics.loadPixel();
3263                                GAds.loadPixel();
3264                                Pinterest.loadPixel();
3265                                TikTok.loadPixel();
3266								Reddit.loadPixel();
3267
3268                                consent.facebook = true;
3269                                consent.bing = true;
3270                                consent.ga = true;
3271                                consent.google_ads = true;
3272                                consent.pinterest = true;
3273                                consent.tiktok = true;
3274								consent.reddit = true;
3275                                consent.gtm = true;
3276
3277                                Utils.setupGDPRData( consent );
3278
3279                            } else if ( button_action === 'disable_all' ) {
3280
3281                                if (typeof CS_Data.cs_meta_ldu_mode == "undefined" || CS_Data.cs_meta_ldu_mode == 0 ) {
3282                                    Facebook.disable();
3283                                    consent.facebook = false;
3284                                }
3285
3286                                if (typeof CS_Data.cs_bing_consent_mode == "undefined" || CS_Data.cs_bing_consent_mode.ad_storage.enabled == 0 ) {
3287                                    Bing.disable();
3288                                    consent.bing = false;
3289                                }
3290
3291                                if ( typeof CS_Data.cs_google_analytics_consent_mode == "undefined" || CS_Data.cs_google_analytics_consent_mode == 0 ) {
3292                                    Analytics.disable();
3293                                    consent.ga = false;
3294                                    consent.gtm = false;
3295                                }
3296
3297                                if ( typeof CS_Data.cs_google_ads_consent_mode == "undefined" || CS_Data.cs_google_ads_consent_mode == 0 ) {
3298                                    GAds.disable();
3299                                    consent.google_ads = false;
3300                                }
3301
3302	                            if ( typeof CS_Data.cs_reddit_ldu_mode == "undefined" || CS_Data.cs_reddit_ldu_mode == 0 ) {
3303		                            Reddit.disable();
3304		                            consent.reddit = false;
3305	                            }
3306
3307                                Pinterest.disable();
3308                                TikTok.disable();
3309
3310                                consent.pinterest = false;
3311                                consent.tiktok = false;
3312
3313                                Utils.setupGDPRData( consent );
3314                            } else if ( button_action === 'cs_confirm' ) {
3315                                consent_actions();
3316                            }
3317                        } );
3318                    }
3319                }
3320
3321                /**
3322                 * Real Cookie Banner
3323                 */
3324                if ( options.gdpr.real_cookie_banner_integration_enabled ) {
3325                    isConcent = true;
3326                    let consentApi = window.consentApi;
3327                    if ( consentApi ) {
3328                        consentApi.consent( "http", "_ga", "*" )
3329                            .then( Analytics.loadPixel.bind( Analytics ), Analytics.disable.bind( Analytics ) );
3330                        consentApi.consent( "http", "1P_JAR", ".google.com" )
3331                            .then( GAds.loadPixel.bind( GAds ), GAds.disable.bind( GAds ) );
3332                        consentApi.consent( "http", "_fbp", "*" )
3333                            .then( Facebook.loadPixel.bind( Facebook ), Facebook.disable.bind( Facebook ) );
3334                        consentApi.consent( "http", "_pinterest_sess", ".pinterest.com" )
3335                            .then( Pinterest.loadPixel.bind( Pinterest ), Pinterest.disable.bind( Pinterest ) );
3336                        consentApi.consent( "http", "_uetsid", "*" )
3337                            .then( Bing.loadPixel.bind( Bing ), Bing.disable.bind( Bing ) );
3338                        consentApi.consent( "http", "tt_webid_v2", ".tiktok.com" )
3339                            .then( TikTok.loadPixel.bind( TikTok ), TikTok.disable.bind( TikTok ) );
3340
3341                        let consent = {
3342                            facebook: true,
3343                            ga: true,
3344                            google_ads: true,
3345                            tiktok: true,
3346                            bing: true,
3347                            pinterest: true,
3348                            gtm: true,
3349                        };
3350
3351                        if (!consentApi.consentSync("http", "_ga", "*").cookieOptIn) {
3352                            consent.ga = false;
3353                            consent.gtm = false;
3354                        }
3355                        if (!consentApi.consentSync("http", "_fbp", "*").cookieOptIn) {
3356                            consent.facebook = false;
3357                        }
3358                        if (!consentApi.consentSync("http", "_pinterest_sess", ".pinterest.com").cookieOptIn) {
3359                            consent.pinterest = false;
3360                        }
3361                        if (!consentApi.consentSync("http", "_uetsid", "*").cookieOptIn) {
3362                            consent.bing = false;
3363                        }
3364                        if (!consentApi.consentSync("http", "1P_JAR", ".google.com").cookieOptIn) {
3365                            consent.google_ads = false;
3366                        }
3367                        if (!consentApi.consentSync("http", "tt_webid_v2", ".tiktok.com").cookieOptIn) {
3368                            consent.tiktok = false;
3369                        }
3370                        Utils.setupGDPRData( consent );
3371
3372                        // load WatchVideo event APIs for Auto
3373                        /**
3374                         * Real Cookie Banner.
3375                         */
3376                        if ( options.hasOwnProperty( 'automatic' ) && options.automatic.enable_video && options.automatic.enable_youtube ) {
3377                            consentApi.consent( "http", "CONSENT", ".youtube.com" ).then( Utils.initYouTubeAPI );
3378                        }
3379
3380                        if ( options.hasOwnProperty( 'automatic' ) && options.automatic.enable_video && options.automatic.enable_vimeo ) {
3381                            consentApi.consent( "http", "player", ".vimeo.com" ).then( Utils.initVimeoAPI );
3382                        }
3383                    }
3384                }
3385
3386                if ( !isConcent ) {
3387                    Utils.initializeVideoAPIs( options );
3388                }
3389            },
3390
3391            setupGDPRData: function ( consent ) {
3392                consent = window.btoa( JSON.stringify( consent ) );
3393                Cookies.set( 'pys_consent', consent, { expires: 365, path: '/', domain: domain } );
3394            },
3395
3396            /**
3397             * Enrich
3398             */
3399            is
3399CheckoutPage: function () {
3400                return $('body').hasClass('woocommerce-checkout') || document.querySelector('.woocommerce-checkout') ||
3401                    $('body').hasClass('edd-checkout');
3402            },
3403            addCheckoutFields : function() {
3404                var utm = "";
3405                var utms = getUTMs()
3406                $.each(utmTerms, function (index, name) {
3407                    if(index > 0) {
3408                        utm+="|";
3409                    }
3410                    utm+=name+":"+utms[name];
3411                });
3412                var utmIdList = "";
3413                var utmsIds = getUTMId()
3414                $.each(utmId, function (index, name) {
3415                    if(index > 0) {
3416                        utmIdList+="|";
3417                    }
3418                    utmIdList+=name+":"+utmsIds[name];
3419                });
3420                var utmIdListLast = "";
3421                var utmsIdsLast = getUTMId(true)
3422                $.each(utmId, function (index, name) {
3423                    if(index > 0) {
3424                        utmIdListLast+="|";
3425                    }
3426                    utmIdListLast+=name+":"+utmsIdsLast[name];
3427                });
3428
3429
3430                var utmLast = "";
3431                var utmsLast = getUTMs(true)
3432                $.each(utmTerms, function (index, name) {
3433                    if(index > 0) {
3434                        utmLast+="|";
3435                    }
3436                    utmLast+=name+":"+utmsLast[name];
3437                });
3438
3439                var dateTime = getDateTime();
3440                var landing = Cookies.get('pys_landing_page');
3441                var lastLanding = Cookies.get('last_pys_landing_page');
3442                var trafic = Cookies.get('pysTrafficSource');
3443                var lastTrafic = Cookies.get('last_pysTrafficSource');
3444
3445                var $form = null;
3446                if($('body').hasClass('woocommerce-checkout')) {
3447                    $form = $("form.woocommerce-checkout");
3448                } else {
3449                    $form = $("#edd_purchase_form");
3450                }
3451                var inputs = {'pys_utm':utm,
3452                    'pys_utm_id':utmIdList,
3453                    'pys_browser_time':dateTime.join("|"),
3454                    'pys_landing':landing,
3455                    'pys_source':trafic,
3456                    'pys_order_type': $(".wcf-optin-form").length > 0 ? "wcf-optin" : "normal",
3457
3458                    'last_pys_landing':lastLanding,
3459                    'last_pys_source':lastTrafic,
3460                    'last_pys_utm':utmLast,
3461                    'last_pys_utm_id':utmIdListLast,
3462                }
3463
3464                Object.keys(inputs).forEach(function(key,index) {
3465                    $form.append("<input type='hidden' name='"+key+"' value='"+inputs[key]+"' /> ");
3466                });
3467
3468
3469            },
3470
3471            /**
3472             * Advanced From Data
3473             */
3474            saveAdvancedFormData: function ( email, phone, firstName, lastName, override = true ) {
3475
3476                if ( !options.cookie.disabled_advanced_form_data_cookie ) {
3477                    let data = Utils.getAdvancedFormData();
3478                    // Ensure data["address"] is an object
3479
3480                    if ( email != null ) {
3481                        if ( !override ) {
3482                            if ( typeof data[ "email" ] === 'undefined' || !data[ "email" ] ) {
3483                                data[ "email" ] = email;
3484                            }
3485                        } else {
3486                            data[ "email" ] = email;
3487                        }
3488
3489                        if ( typeof data[ "emails" ] === 'object' ) {
3490                            if ( override ) {
3491                                data[ "emails" ] = [ email, ...Object.values( data[ "emails" ] ) ];
3492                            } else {
3493                                data[ "emails" ] = [ ...Object.values( data[ "emails" ] ), email ];
3494                            }
3495                        } else {
3496                            data[ "emails" ] = [ email ];
3497                        }
3498                        data[ "emails" ] = [ ...new Set( data[ "emails" ] ) ];
3499                        data[ "emails" ] = data[ "emails" ].slice( 0, 3 );
3500                    }
3501
3502                    if ( phone != null ) {
3503                        if ( !override ) {
3504                            if ( typeof data[ "phone" ] === 'undefined' || !data[ "phone" ] ) {
3505                                data[ "phone" ] = phone;
3506                            }
3507                        } else {
3508                            data[ "phone" ] = phone;
3509                        }
3510
3511                        if ( typeof data[ "phones" ] === 'object' ) {
3512                            if ( override ) {
3513                                data[ "phones" ] = [ phone, ...Object.values( data[ "phones" ] ) ];
3514                            } else {
3515                                data[ "phones" ] = [ ...Object.values( data[ "phones" ] ), phone ];
3516                            }
3517                        } else {
3518                            data[ "phones" ] = [ phone ];
3519                        }
3520                        data[ "phones" ] = [ ...new Set( data[ "phones" ] ) ];
3521                        data[ "phones" ] = data[ "phones" ].slice( 0, 3 );
3522                    }
3523
3524                    if ( firstName != null ) {
3525                        if ( !override ) {
3526                            if ( typeof data[ "first_name" ] === 'undefined' || !data[ "first_name" ] ) {
3527                                data[ "first_name" ] = firstName;
3528                            }
3529                        } else {
3530                            data[ "first_name" ] = firstName;
3531                        }
3532
3533                        if ( typeof data[ "fns" ] === 'object' ) {
3534                            if ( override ) {
3535                                data[ "fns" ] = [ firstName, ...Object.values( data[ "fns" ] ) ];
3536                            } else {
3537                                data[ "fns" ] = [ ...Object.values( data[ "fns" ] ), firstName ];
3538                            }
3539                        } else {
3540                            data[ "fns" ] = [ firstName ];
3541                        }
3542                        data[ "fns" ] = [ ...new Set( data[ "fns" ] ) ];
3543                        data[ "fns" ] = data[ "fns" ].slice( 0, 2 );
3544                    }
3545
3546                    if ( lastName != null ) {
3547                        if ( !override ) {
3548                            if ( typeof data[ "last_name" ] === 'undefined' || !data[ "last_name" ] ) {
3549                                data[ "last_name" ] = lastName;
3550                            }
3551                        } else {
3552                            data[ "last_name" ] = lastName;
3553                        }
3554
3555                        if ( typeof data[ "lns" ] === 'object' ) {
3556                            if ( override ) {
3557                                data[ "lns" ] = [ lastName, ...Object.values( data[ "lns" ] ) ];
3558                            } else {
3559                                data[ "lns" ] = [ ...Object.values( data[ "fns" ] ), lastName ];
3560                            }
3561                        } else {
3562                            data[ "lns" ] = [ lastName ];
3563                        }
3564                        data[ "lns" ] = [ ...new Set( data[ "lns" ] ) ];
3565                        data[ "lns" ] = data[ "lns" ].slice( 0, 2 );
3566                    }
3567
3568                    Cookies.set( 'pys_advanced_form_data', JSON.stringify( data ), { expires: 300,path: '/',domain: domain } );
3569                } else {
3570                    Cookies.remove( 'pys_advanced_form_data', { path: '/',domain: domain } )
3571                }
3572                if(GTM.isEnabled()){
3573                    GTM.updateEnhancedConversionData();
3574                }
3575                if(Analytics.isEnabled()){
3576                    Analytics.updateEnhancedConversionData();
3577                } else if ( GAds.isEnabled() ) {
3578                    GAds.updateEnhancedConversionData();
3579                }
3580                if ( Bing.isEnabled() && typeof Bing.updateEnhancedConversionData === 'function' ) {
3581                    Bing.updateEnhancedConversionData();
3582                }
3583            },
3584            getAdvancedMergeFormData: function (allways_provided_data = false) {
3585                const advanced = Utils.getAdvancedFormData();
3586                let mergedData = {},
3587                    limit = options.tracking_analytics.use_multiple_provided_data || allways_provided_data ? 3 : 1,
3588                    address_limit = options.tracking_analytics.use_multiple_provided_data || allways_provided_data ? 2 : 1;
3589
3590                if ( options.tracking_analytics.use_encoding_provided_data || allways_provided_data) {
3591                    mergedData.sha256_email_address = [];
3592                    mergedData.sha256_phone_number = [];
3593                    mergedData.address = [];
3594                    if ( options.tracking_analytics.hasOwnProperty( "userData" ) ) {
3595                        if ( options.tracking_analytics.userData.hasOwnProperty( "emails" ) && Object.keys( options.tracking_analytics.userData.emails ).length > 0 ) {
3596                            Object.keys( options.tracking_analytics.userData.emails ).forEach( ( key ) => {
3597                                mergedData.sha256_email_address.push( sha256( options.tracking_analytics.userData.emails[ key ] ) );
3598                            } )
3599                        }
3600                        if ( options.tracking_analytics.userData.hasOwnProperty( "phones" ) && Object.keys( options.tracking_analytics.userData.phones ).length > 0 ) {
3601                            Object.keys( options.tracking_analytics.userData.phones ).forEach( ( key ) => {
3602                                mergedData.sha256_phone_number.push( sha256( options.tracking_analytics.userData.phones[ key ] ) );
3603                            } )
3604                        }
3605                        if ( options.tracking_analytics.userData.hasOwnProperty( "addresses" ) && Object.keys( options.tracking_analytics.userData.addresses ).length > 0 ) {
3606                            Object.keys( options.tracking_analytics.userData.addresses ).forEach( ( key ) => {
3607                                let address = Object.assign( {}, options.tracking_analytics.userData.addresses[ key ] );
3608
3609                                if ( address.first_name ) {
3610                                    address.sha256_first_name = address.first_name !== '' ? sha256( address.first_name ) : '';
3611                                    delete address.first_name;
3612                                }
3613                                if ( address.last_name ) {
3614                                    address.sha256_last_name = address.last_name !== '' ? sha256( address.last_name ) : '';
3615                                    delete address.last_name;
3616                                }
3617                                mergedData.address.push( address );
3618                            } )
3619                        }
3620                    }
3621
3622                    let data_persistency = options.data_persistency;
3623
3624                    //emails
3625                    if ( advanced.emails && Object.keys( advanced.emails ).length > 0 ) {
3626                        Object.keys( advanced.emails ).forEach( ( ke
3626y ) => {
3627                            if ( data_persistency === 'recent_data' ) {
3628                                mergedData.sha256_email_address.push( sha256( advanced.emails[ key ] ) );
3629                            } else {
3630                                mergedData.sha256_email_address.unshift( sha256( advanced.emails[ key ] ) );
3631                            }
3632                        } )
3633                    }
3634                    if ( advanced.email && advanced.email !== '' ) {
3635                        if ( data_persistency === 'recent_data' ) {
3636                            mergedData.sha256_email_address.push( sha256( advanced.email ) );
3637                        } else {
3638                            mergedData.sha256_email_address.unshift( sha256( advanced.email ) );
3639                        }
3640                    }
3641                    mergedData.sha256_email_address = [ ...new Set( mergedData.sha256_email_address ) ];
3642                    mergedData.sha256_email_address = mergedData.sha256_email_address.slice( 0, limit );
3643
3644                    //phones
3645                    if ( advanced.phones && Object.keys( advanced.phones ).length > 0 ) {
3646                        Object.keys( advanced.phones ).forEach( ( key ) => {
3647                            if ( data_persistency === 'recent_data' ) {
3648                                mergedData.sha256_phone_number.push( sha256( advanced.phones[ key ] ) );
3649                            } else {
3650                                mergedData.sha256_phone_number.unshift( sha256( advanced.phones[ key ] ) );
3651                            }
3652                        } )
3653                    }
3654                    if ( advanced.phone && advanced.phone !== '' ) {
3655                        if ( data_persistency === 'recent_data' ) {
3656                            mergedData.sha256_phone_number.push( sha256( advanced.phone ) );
3657                        } else {
3658                            mergedData.sha256_phone_number.unshift( sha256( advanced.phone ) );
3659                        }
3660                    }
3661                    mergedData.sha256_phone_number = [ ...new Set( mergedData.sha256_phone_number ) ];
3662                    mergedData.sha256_phone_number = mergedData.sha256_phone_number.slice( 0, limit );
3663
3664                    //first and last names
3665                    if ( advanced.fns && Object.keys( advanced.fns ).length > 0 ) {
3666                        Object.entries( advanced.fns ).forEach( ( item ) => {
3667                            if ( mergedData.address.length < address_limit ) {
3668                                let first_name = item[ 1 ];
3669                                let last_name = ( advanced.lns && Object.keys( advanced.lns ).length > 0 ) ? ( advanced.lns[ item[ 0 ] ] ? advanced.lns[ item[ 0 ] ] : advanced.lns[ 0 ] ) : '';
3670                                let address = {
3671                                    sha256_first_name: first_name !== '' ? sha256( first_name ) : '',
3672                                    sha256_last_name: last_name !== '' ? sha256( last_name ) : '',
3673                                    // Add other address properties here if they exist in advanced
3674                                };
3675                                mergedData.address.push( address );
3676                            }
3677                        } )
3678                    }
3679
3680                    if ( advanced.first_name || advanced.last_name ) {
3681                        if ( mergedData.address.length < address_limit ) {
3682                            let address = {
3683                                sha256_first_name: advanced.first_name !== '' ? sha256( advanced.first_name ) : '',
3684                                sha256_last_name: advanced.last_name !== '' ? sha256( advanced.last_name ) : '',
3685                                // Add other address properties here if they exist in advanced
3686                            };
3687                            mergedData.address.push( address );
3688                        }
3689                    }
3690                } else {
3691                    mergedData.email = [];
3692                    mergedData.phone_number = [];
3693                    mergedData.address = [];
3694                    if ( options.tracking_analytics.hasOwnProperty( "userData" ) ) {
3695                        if ( options.tracking_analytics.userData.hasOwnProperty( "emails" ) && Object.keys( options.tracking_analytics.userData.emails ).length > 0 ) {
3696                            Object.keys( options.tracking_analytics.userData.emails ).forEach( ( ke
3696y ) => {
3697                                mergedData.email.push( options.tracking_analytics.userData.emails[ key ] );
3698                            } )
3699                        }
3700                        if ( options.tracking_analytics.userData.hasOwnProperty( "phones" ) && Object.keys( options.tracking_analytics.userData.phones ).length > 0 ) {
3701                            Object.keys( options.tracking_analytics.userData.phones ).forEach( ( key ) => {
3702                                mergedData.phone_number.push( options.tracking_analytics.userData.phones[ key ] );
3703                            } )
3704                        }
3705                        if ( options.tracking_analytics.userData.hasOwnProperty( "addresses" ) && Object.keys( options.tracking_analytics.userData.addresses ).length > 0 ) {
3706                            Object.keys( options.tracking_analytics.userData.addresses ).forEach( ( key ) => {
3707                                mergedData.address.push( options.tracking_analytics.userData.addresses[ key ] );
3708                            } )
3709                        }
3710                    }
3711
3712                    let data_persistency = options.data_persistency;
3713
3714                    //emails
3715                    if ( advanced.emails && Object.keys( advanced.emails ).length > 0 ) {
3716                        Object.keys( advanced.emails ).forEach( ( key ) => {
3717                            if ( data_persistency === 'recent_data' ) {
3718                                mergedData.email.push( advanced.emails[ key ] );
3719                            } else {
3720                                mergedData.email.unshift( advanced.emails[ key ] );
3721                            }
3722                        } )
3723                    }
3724                    if ( advanced.email && advanced.email !== '' ) {
3725                        if ( data_persistency === 'recent_data' ) {
3726                            mergedData.email.push( advanced.email );
3727                        } else {
3728                            mergedData.email.unshift( advanced.email );
3729                        }
3730                    }
3731                    mergedData.email = [ ...new Set( mergedData.email ) ];
3732                    mergedData.email = mergedData.email.slice( 0, limit );
3733
3734                    //phones
3735                    if ( advanced.phones && Object.keys( advanced.phones ).length > 0 ) {
3736                        Object.keys( advanced.phones ).forEach( ( key ) => {
3737                            if ( data_persistency === 'recent_data' ) {
3738                                mergedData.phone_number.push( advanced.phones[ key ] );
3739                            } else {
3740                                mergedData.phone_number.unshift( advanced.phones[ key ] );
3741                            }
3742                        } )
3743                    }
3744                    if ( advanced.phone && advanced.phone !== '' ) {
3745                        if ( data_persistency === 'recent_data' ) {
3746                            mergedData.phone_number.push( advanced.phone );
3747                        } else {
3748                            mergedData.phone_number.unshift( advanced.phone );
3749                        }
3750                    }
3751                    mergedData.phone_number = [ ...new Set( mergedData.phone_number ) ];
3752                    mergedData.phone_number = mergedData.phone_number.slice( 0, limit );
3753
3754                    //first and last names
3755                    if ( advanced.fns && Object.keys( advanced.fns ).length > 0 ) {
3756                        Object.entries( advanced.fns ).forEach( ( item ) => {
3757                            if ( mergedData.address.length < address_limit ) {
3758                                let first_name = item[ 1 ];
3759                                let last_name = ( advanced.lns && Object.keys( advanced.lns ).length > 0 ) ? ( advanced.lns[ item[ 0 ] ] ? advanced.lns[ item[ 0 ] ] : advanced.lns[ 0 ] ) : '';
3760                                let address = {
3761                                    first_name: first_name || '',
3762                                    last_name: last_name || '',
3763                                    // Add other address properties here if they exist in advanced
3764                                };
3765                                mergedData.address.push( address );
3766                            }
3767                        } )
3768                    }
3769
3770                    if ( advanced.first_name || advanced.last_name ) {
3771                        if ( mergedData.address.length < address_limit ) {
3772                            let address = {
3773                                first_name: advanced.first_name || '',
3774                                last_name: advanced.last_name || '',
3775                                // Add other address properties here if they exist in advanced
3776                            };
3777                            mergedData.address.push( address );
3778                        }
3779                    }
3780                }
3781
3782                Utils.removeEmptyProperties( mergedData );
3783                return mergedData;
3784            },
3785            removeEmptyProperties : function(obj) {
3786
3787                if (obj.hasOwnProperty('address')) {
3788                    // Iterate over each array in 'address'
3789                    for (let i = 0; i < obj['address'].length; i++) {
3790                        let address1 = obj['address'][i];
3791
3792                        // Compare with every other array in 'address'
3793                        for (let j = i + 1; j < obj['address'].length; j++) {
3794                            let address2 = obj['address'][j];
3795
3796                            // If duplicate properties are found, remove them from address2
3797                            for (let prop in address1) {
3798                                if (address1[prop] === address2[prop]) {
3799                                    delete address2[prop];
3800                                }
3801                            }
3802                        }
3803                    }
3804                }
3805
3806                for (let key in obj) {
3807                    if (obj[key] === null || obj[key] === undefined || obj[key] === '') {
3808                        delete obj[key];
3809                    } else if (Array.isArray(obj[key])) {
3810                        obj[key] = [...new Set(obj[key])]; // Remove duplicates from the array
3811                        obj[key] = obj[key].filter(item => item !== null && item !== undefined && item !== '');
3812                        // Process objects inside arrays
3813                        obj[key] = obj[key].map(item => {
3814                            if (item === null) {
3815                                return; // Skip null elements
3816                            } else if (Array.isArray(item)) {
3817                                return this.removeEmptyProperties(item);
3818                            } else if (typeof item === 'object') {
3819                                let cleanedItem = this.removeEmptyProperties(item);
3820                                if (Object.keys(cleanedItem).length > 0) {
3821                                    return cleanedItem;
3822                                }
3823                            } else {
3824                                return item;
3825                            }
3826                        });
3827                        // Remove empty objects and null values from the array
3828                        obj[key] = obj[key].filter(item => item !== undefined && !(typeof item === 'object' && Object.keys(item).length === 0));
3829                        if (obj[key].length === 0) {
3830                            delete obj[key];
3831                        }
3832                    } else if (typeof obj[key] === 'object') {
3833                        this.removeEmptyProperties(obj[key]);
3834                        if (Object.keys(obj[key]).length === 0) {
3835                            delete obj[key];
3836                        }
3837                    }
3838                }
3839                return obj;
3840            },
3841            getAdvancedFormData: function () {
3842                let dataStr = Cookies.get("pys_advanced_form_data");
3843                if(dataStr === undefined) {
3844                    return {'first_name':"",'last_name':"",'email':"",'phone':"",'fns':[],'lns':[],'emails':[],'phones':[]};
3845                } else {
3846                    return JSON.parse(dataStr);
3847                }
3848            },
3849
3850            getFormFilledData: function ( event ) {
3851                // First, resolve static/dynamic parameters
3852                if (event.params && Object.keys(event.params).length > 0) {
3853                    Object.entries(event.params).forEach(([key, value]) => {
3854                        // Resolve parameter value (static or dynamic)
3855                        const resolvedValue = resolveParamValue(value, key);
3856                        if (resolvedValue !== null) {
3857                            event.params[key] = resolvedValue;
3858                        }
3859                        else {
3860                            delete event.params[key];
3861                        }
3862                    });
3863                }
3864
3865                // Then, handle dynamic fields from cookies (existing logic)
3866
3867                if ( Object.keys(options.track_dynamic_fields).length > 0 && Object.keys(event.params).length > 0 ) {
3868                    Object.entries(event.params).forEach((item) => {
3869
3870                        if ( options.track_dynamic_fields.hasOwnProperty(item[0]) ) {
3871                            let fieldData = Cookies.get('pys_dyn_field_' + item[1] );
3872
3873                            if(fieldData !== undefined && fieldData !== '') {
3874                                event.params[item[0]] = fieldData;
3875                            } else {
3876                                delete event.params[item[0]];
3877                            }
3878                        }
3879                    })
3880                }
3881                return event;
3882            },
3883
3884	        registerGadsPhoneConversion( conversion_id ) {
3885		        // Ads phone call conversion
3886		        if ( options.triggerEventTypes.hasOwnProperty( 'gads_phone_conversion' ) ) {
3887			        Object.entries( options.triggerEventTypes.gads_phone_conversion ).forEach( function ( [ trigger_id, data ] ) {
3888				        if ( data.enabled && Object.entries( data.numbers ).length > 0 ) {
3889
3890					        let allowed_pixels = [];
3891					        Object.entries( options.triggerEvents[ trigger_id ] ).forEach( function ( [ pixel, pixel_data ] ) {
3892						        if ( pixel !== 'google_ads' ) {
3893							        return;
3894						        }
3895
3896						        allowed_pixels.push( ...pixel_data.conversion_ids );
3897					        } )
3898
3899					        if ( !allowed_pixels.includes( conversion_id ) ) {
3900						        return;
3901					        }
3902
3903					        data.numbers.forEach( function ( pair ) {
3904						        if ( !pair.number || !pair.label ) {
3905							        return;
3906						        }
3907
3908						        let phoneCb = function () {
3909							        Utils.fireTriggerEvent( trigger_id )
3910						        };
3911
3912						        gtag( 'config', conversion_id + '/' + pair.label, {
3913							        phone_conversion_number: pair.number,
3914							        phone_conversion_callback: phoneCb
3915						        } );
3916					        } )
3917				        }
3918			        } );
3919		        }
3920	        }
3921        }
3922
3923
3924    }(options);
3925
3926    var TikTok = function (options) {
3927
3928        var initialized = false;
3929
3930        function fireEvent(name, event) {
3931
3932            if(typeof window.pys_event_data_filter === "function" && window.pys_disable_event_filter(name,'tiktok')) {
3933                return;
3934            }
3935
3936            var data = event.params;
3937
3938            var ids = event.pixelIds.filter(function (pixelId) {
3939                return !Utils.hideMatchingPixel(pixelId, 'tiktok');
3940            })
3941            var params = {};
3942            Utils.copyProperties(data, params);
3943
3944            params.eventID = Utils.generateUniqueId(event);
3945
3946            if(ids.length > 0){
3947                TikTok.fireEventAPI(name, event, params);
3948            }
3949            ids.forEach(function(pixelId){
3950                if (options.debug) {
3951                    console.log('[TikTok] ' + name, params,"pixel_id",pixelId);
3952                }
3953
3954                ttq.instance(pixelId).track(name,params)
3955
3956            });
3957
3958            var customEvent = new CustomEvent('tiktok_event_sent', {
3959                detail: {
3960                    eventName: name,
3961                    params: params,
3962                    pixel_ids: ids
3963                }
3964            });
3965            window.dispatchEvent(customEvent);
3966        }
3967
3968        return {
3969            tag: function() {
3970                return "tiktok";
3971            },
3972            isEnabled: function () {
3973                return options.hasOwnProperty('tiktok');
3974            },
3975            getHidePixel: function(){
3976                if(this.isEnabled() && options.tiktok.hasOwnProperty('hide_pixels'))
3977                {
3978                    return options.tiktok.hide_pixels;
3979                }
3980                return [];
3981            },
3982            disable: function () {
3983                initialized = false;
3984            },
3985
3986            loadPixel:function () {
3987                if (initialized || !this.isEnabled() || !Utils.consentGiven('tiktok')) {
3988                    return;
3989                }
3990                for (var i = 0; i < options.tiktok.pixelIds.length; i++) {
3991                    var trackingId = options.tiktok.pixelIds[i];
3992                    if (!Utils.hideMatchingPixel(trackingId, 'tiktok')) {
3993                        !function (w, d, t) {
3994                            w.TiktokAnalyticsObject=t;
3995                            var ttq=w[t]=w[t]||[];
3996                            ttq.methods=["page","track","identify","instances","debug","on","off","once","ready","alias","group","enableCookie","disableCookie"];
3997                            ttq.setAndDefer=function(t,e){t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}};
3998                            for(var i=0;i<ttq.methods.length;i++)
3999                                ttq.setAndDefer(ttq,ttq.methods[i]);
4000                            ttq.instance=function(t){for(var e=ttq._i[t]||[],n=0;n<ttq.methods.length;n++)ttq.setAndDefer(e,ttq.methods[n]);return e};
4001                            ttq.load=function(e,n){var i="https://analytics.tiktok.com/i18n/pixel/events.js";ttq._i=ttq._i||{},ttq._i[e]=[],ttq._i[e]._u=i,ttq._t=ttq._t||{},ttq._t[e]=+new Date,ttq._o=ttq._o||{},ttq._o[e]=n||{};var o=document.createElement("script");o.type="text/javascript",o.async=!0,o.src=i+"?sdkid="+e+"&lib="+t;var a=document.getElementsByTagName("script")[0];a.parentNode.insertBefore(o,a)};
4002
4003                            //ttq.load('C60QSCQRVDG9JAKNPK2G');
4004                            //ttq.page();
4005                        }(window, document, 'ttq');
4006                        break;
4007                    }
4008                }
4009
4010
4011                var ids = options.tiktok.pixelIds.filter(function (pixelId) {
4012                    return !Utils.hideMatchingPixel(pixelId, 'tiktok');
4013                })
4014                ids.forEach(function (pixelId) {
4015
4016                    ttq.load(pixelId);
4017                    ttq.page();
4018                    let advancedMatching = {};
4019                    if(options.tiktok.hasOwnProperty('advanced_matching')
4020                        && Object.keys(options.tiktok.advanced_matching).length > 0) {
4021                        advancedMatching = options.tiktok.advanced_matching;
4022                        if(!advancedMatching.hasOwnProperty("external_id")){
4023                            if (Cookies.get('pbid')) {
4024                                advancedMatching["external_id"] = Cookies.get('pbid');
4025                            }
4026                        }
4027                        else if(advancedMatching.hasOwnProperty("external_id") && advancedMatching.external_id != Cookies.get('pbid'))
4028                        {
4029                            advancedMatching["external_id"] = Cookies.get('pbid') ? Cookies.get('pbid') : advancedMatching.external_id;
4030                        }
4031
4032                        ttq.instance(pixelId).identify(advancedMatching)
4033                    }
4034                });
4035                initialized = true;
4036
4037                if (options.staticEvents.hasOwnProperty('tiktok')) {
4038                    var timeout = 1;
4039                    setTimeout(function (timeout) {
4040                        Utils.fireStaticEvents('tiktok', timeout);
4041                    }, 1500, timeout)
4042                }
4043            },
4044
4045            fireEvent: function (name, data) {
4046                if (!initialized || !this.isEnabled()) {
4047                    return false;
4048                }
4049                data.delay = data.delay || 0;
4050
4051                if (data.delay === 0) {
4052                    fireEvent(name, data);
4053                } else {
4054                    setTimeout(function (name, params) {
4055                        fireEvent(name, params);
4056                    }, data.delay * 1000, name, data);
4057                }
4058                return true;
4059            },
4060
4061            fireEventAPI: function (name, event, params) {
4062
4063                var ids = event.pixelIds.filter(function (pixelId) {
4064                    return !Utils.hideMatchingPixel(pixelId, 'tiktok');
4065                })
4066                var notCachedEventsIds = new Array();
4067                var isAddToCartFromJs =  options.woo.hasOwnProperty("addToCartCatchMethod")
4068                    && options.woo.addToCartCatchMethod === "add_cart_js";
4069                if(!isAddToCartFromJs) {
4070                    notCachedEventsIds.push('woo_add_to_cart_on_button_click')
4071                }
4072
4073                if(options.tiktok.serverApiEnabled) {
4074                    if(!notCachedEventsIds.includes(event.e_id)) {
4075
4076                        var isApiDisabled = options.gdpr.all_disabled_by_api ||
4077                            options.gdpr.tiktok_disabled_by_api ||
4078                            options.gdpr.cookiebot_integration_enabled ||
4079                            options.gdpr.cookie_notice_integration_enabled ||
4080                            options.gdpr.consent_magic_integration_enabled ||
4081                            options.gdpr.cookie_law_info_integration_enabled;
4082                        // Update eventID
4083
4084                        // send event from server if they were block by gdpr or need send with delay
4085                        if( options.ajaxForServerEvent || isApiDisabled || event.delay > 0 || event.type !== "static" ){
4086
4087                            var json = {
4088                                action: 'pys_tiktok_api_event',
4089                                pixel: TikTok.tag(),
4090                                event: name,
4091                                event_slug: event.e_id,
4092                                ids: ids,
4093                                data:params,
4094                                url:window.location.href,
4095                                event_id:params.eventID,
4096                                ajax_event:options.ajax_event
4097                            };
4098
4099                            let delay = 0;
4100                            try {
4101                                if (sessionStorage) {
4102                                    Object.keys(sessionStorage)
4103                                        .filter(key => key.startsWith('wc_fragments_'))
4104                                        .forEach((key) => {
4105                                            let value = sessionStorage.getItem(key);
4106                                            if (event.e_id === 'woo_add_to_cart_on_button_click') {
4107                                                delay = 2000;
4108                                            }
4109                                        });
4110                                }
4111                            } catch (error) {
4112                                console.error('sessionStorage is not accessible:', error);
4113                            }
4114
4115
4116                            if(event.hasOwnProperty('woo_order')) {
4117                                json['woo_order'] = event.woo_order;
4118                            }
4119
4120                            if(event.hasOwnProperty('edd_order')) {
4121                                json['edd_order'] = event.edd_order;
4122                            }
4123                            if (event.e_id === "automatic_event_internal_link" || event.e_id === "automatic_event_outbound_link" || name == 'PageView') {
4124                                delay = delay === 0 ? 500 : delay;
4125                                setTimeout(() => Utils.sendServerAjaxRequest(options.ajaxUrl, json), delay);
4126                            } else if (event.type != 'static') {
4127                                setTimeout(() => Utils.sendServerAjaxRequest(options.ajaxUrl, json), delay);
4128                            }
4129
4130                            if ( ( event.type == 'static' && options.ajaxForServerStaticEvent ) || ( event.hasOwnProperty( 'ajaxFire' ) && event.ajaxFire ) ) {
4131                                setTimeout( () => Utils.sendServerAjaxRequest( options.ajaxUrl, json ), delay );
4132                            }
4133                        }
4134                    }
4135                }
4136            },
4137
4138            onClickEvent: function (event) {
4139                this.fireEvent(event.name, event);
4140            },
4141
4142            onWooAddToCartOnSingleEvent: function (product_id, qty, product_type, is_external, $form) {
4143
4144                window.pysWooProductData = window.pysWooProductData || [];
4145                if (!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
4146                    return;
4147
4148                if (window.pysWooProductData.hasOwnProperty(product_id)) {
4149                    if (window.pysWooProductData[product_id].hasOwnProperty(this.tag())) {
4150
4151                        var event = Utils.clone(options.dynamicEvents.woo_add_to_cart_on_button_click[this.tag()]);
4152
4153                        Utils.copyProperties(window.pysWooProductData[product_id][this.tag()]['params'], event.params);
4154
4155                        // maybe customize value option
4156                        if (options.woo.addToCartOnButtonValueEnabled && options.woo.addToCartOnButtonValueOption !== 'global') {
4157
4158                            if (product_type === Utils.PRODUCT_BUNDLE) {
4159                                var data = $(".bundle_form .bundle_data").data("bundle_form_data");
4160                                var items_sum = getBundlePriceOnSingleProduct(data);
4161                                event.params.value = (parseFloat(data.base_price) + items_sum) * qty;
4162                            } else {
4163                                event.params.value = event.params.value * qty;
4164                            }
4165                        }
4166
4167                        event.params.quantity = qty;
4168
4169                        this.fireEvent(event.name, event);
4170
4171                    }
4172                }
4173            },
4174
4175            onWooAddToCartOnButtonEvent: function (product_id) {
4176                if(!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
4177                    return;
4178
4179                if (window.pysWooProductData.hasOwnProperty(product_id)) {
4180                    if (window.pysWooProductData[product_id].hasOwnProperty(this.tag())) {
4181                        var productData = window.pysWooProductData[product_id][this.tag()]
4182                        var event = Utils.clone(options.dynamicEvents.woo_add_to_cart_on_button_click[this.tag()])
4183
4184                        Utils.copyProperties(productData['params'], event.params)
4185                        event.pixelIds = productData['pixelIds'];
4186                        this.fireEvent(event.name, event);
4187                    }
4188                }
4189            },
4190
4191            onEddAddToCartOnButtonEvent : function (download_id, price_index, qty) {
4192                if(!options.dynamicEvents.edd_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
4193                    return;
4194                var event = Utils.clone(options.dynamicEvents.edd_add_to_cart_on_button_click[this.tag()]);
4195
4196
4197                if (window.pysEddProductData.hasOwnProperty(download_id)) {
4198
4199                    var index;
4200
4201                    if (price_index) {
4202                        index = download_id + '_' + price_index;
4203                    } else {
4204                        index = download_id;
4205                    }
4206
4207                    if (window.pysEddProductData[download_id].hasOwnProperty(index)) {
4208                        if (window.pysEddProductData[download_id][index].hasOwnProperty(this.tag())) {
4209
4210                            Utils.copyProperties(window.pysEddProductData[download_id][index][this.tag()].params, event.params);
4211                            this.fireEvent(event.name,event);
4212
4213                        }
4214                    }
4215
4216                }
4217            },
4218
4219            onPageScroll: function (event) {
4220                if (initialized && this.isEnabled()) {
4221                    this.fireEvent(event.name, event);
4222                }
4223            },
4224
4225            onWatchVideo: function (event) {
4226                if (initialized && this.isEnabled() && !event.fired) {
4227                    this.fireEvent(event.name, event);
4228                }
4229            },
4230
4231            onCommentEvent: function (event) {
4232                if (initialized && this.isEnabled()) {
4233                    this.fireEvent(event.name, event);
4234                }
4235            },
4236
4237            onAdSenseEvent: function (event) {
4238                if (initialized && this.isEnabled()) {
4239                    this.fireEvent(event.name, event);
4240                }
4241            },
4242
4243            onTime: function (event) {
4244                if (initialized && this.isEnabled()) {
4245                    this.fireEvent(event.name, event);
4246                }
4247            },
4248        }
4249    }(options);
4250
4251    var Facebook = function (options) {
4252
4253        var defaultEventTypes = [
4254            'PageView',
4255            'ViewContent',
4256            'Search',
4257            'AddToCart',
4258            'AddToWishlist',
4259            'InitiateCheckout',
4260            'AddPaymentInfo',
4261            'Purchase',
4262            'Lead',
4263
4264            'Subscribe',
4265            'CustomizeProduct',
4266            'FindLocation',
4267            'StartTrial',
4268            'SubmitApplication',
4269            'Schedule',
4270            'Contact',
4271            'Donate'
4272        ];
4273
4274        var notCachedEventsIds = new Array();
4275        var isAddToCartFromJs =  options.woo.hasOwnProperty("addToCartCatchMethod")
4276            && options.woo.addToCartCatchMethod === "add_cart_js";
4277        if(!isAddToCartFromJs) {
4278            notCachedEventsIds.push('woo_add_to_cart_on_button_click')
4279        }
4280
4281        var initialized = false;
4282
4283        var genereateFbp = function (){
4284            return !Cookies.get('_fbp') ? 'fb.1.'+Date.now()+'.'+Math.floor(1000000000 + Math.random() * 9000000000) : Cookies.get('_fbp');
4285        };
4286        var genereateFbc = function (){
4287            return getUrlParameter('fbclid') ? 'fb.1.'+Date.now()+'.'+getUrlParameter('fbclid') : ''
4288        };
4289
4290        var configuredPixels = new Array();
4291        function fireEvent(name, event) {
4292
4293
4294            if(typeof window.pys_event_data_filter === "function" && window.pys_disable_event_filter(name,'facebook')) {
4295                return;
4296            }
4297
4298            var data = event.params;
4299            var ids = event.pixelIds.filter(function (pixelId) {
4300                return !Utils.hideMatchingPixel(pixelId, 'facebook');
4301            });
4302
4303            var actionType = defaultEventTypes.includes(name) ? 'trackSingle' : 'trackSingleCustom';
4304
4305            var params = {};
4306
4307            Utils.copyProperties(data, params);
4308            Utils.copyProperties(Utils.getRequestParams(), params);
4309            Utils.copyProperties(Utils.getRequestParams(), data);
4310
4311            params = Facebook.filterParams(params);
4312
4313
4314            if(options.facebook.serverApiEnabled) {
4315                if(event.e_id === "woo_remove_from_cart" ) {
4316                    Facebook.updateEventId(event.name);
4317                    event.eventID = Facebook.getEventId(event.name);
4318                } else if(!notCachedEventsIds.includes(event.e_id)) {
4319                    var isApiDisabled = options.gdpr.all_disabled_by_api ||
4320                        options.gdpr.facebook_disabled_by_api ||
4321                        options.gdpr.cookiebot_integration_enabled ||
4322                        options.gdpr.cookie_notice_integration_enabled ||
4323                        options.gdpr.consent_magic_integration_enabled ||
4324                        options.gdpr.cookie_law_info_integration_enabled;
4325                    // Update eventID
4326
4327                    event.eventID = Utils.generateUniqueId(event);
4328
4329                    if(Cookies.get('_fbp')){
4330                        params._fbp = Cookies.get('_fbp');
4331                    }
4332                    if(Cookies.get('_fbc')){
4333                        params._fbc = Cookies.get('_fbc');
4334                    }
4335                    // send event from server if they was bloc by gdpr or need send with delay
4336                    if( options.ajaxForServerEvent || isApiDisabled ){
4337                        var json = {
4338                            action: 'pys_api_event',
4339                            pixel: 'facebook',
4340                            event: name,
4341                            event_slug: event.e_id,
4342                            ids: ids,
4343                            data:params,
4344                            url:window.location.href,
4345                            eventID:event.eventID,
4346                            ajax_event:options.ajax_event
4347                        };
4348
4349                        if(event.hasOwnProperty('woo_order')) {
4350                            json['woo_order'] = event.woo_order;
4351                        }
4352
4353                        if(event.hasOwnProperty('edd_order')) {
4354                            json['edd_order'] = event.edd_order;
4355                        }
4356
4357                        let delay = 0;
4358                        try {
4359                            if (sessionStorage) {
4360                                Object.keys(sessionStorage)
4361                                    .filter(key => key.startsWith('wc_fragments_'))
4362                                    .forEach((key) => {
4363                                        let value = sessionStorage.getItem(key);
4364                                        if (event.e_id === 'woo_add_to_cart_on_button_click') {
4365                                            delay = 2000;
4366                                        }
4367                                    });
4368                            }
4369                        } catch (error) {
4370                            console.error('sessionStorage is not accessible:', error);
4371                        }
4372
4373                        if (event.e_id === "automatic_event_internal_link" || event.e_id === "automatic_event_outbound_link") {
4374                            delay = delay === 0 ? 500 : delay;
4375                            setTimeout(() => Utils.sendServerAjaxRequest(options.ajaxUrl, json), delay);
4376                        } else if (event.type != 'static') {
4377                            setTimeout(() => Utils.sendServerAjaxRequest(options.ajaxUrl, json), delay);
4378                        }
4379
4380                        if ( ( event.type == 'static' && options.ajaxForServerStaticEvent ) || ( event.hasOwnProperty( 'ajaxFire' ) && event.ajaxFire ) ) {
4381                            setTimeout( () => Utils.sendServerAjaxRequest( options.ajaxUrl, json ), delay );
4382                        }
4383                    }
4384
4385                    if( event.e_id !== "automatic_event_signup" && name == "CompleteRegistration" && options.facebook.wooCRSendFromServer ) {
4386                        return;
4387                    }
4388                }
4389
4390            }
4391            delete params._fbp;
4392            delete params._fbc;
4393            if (options.debug) {
4394                console.log('[Facebook] ' + name, params,"pixel_ids",ids,"eventID",event.eventID);
4395            }
4396            // fire event for each pixel id
4397            ids.forEach(function (pixelId) {
4398                // add eventID for deduplicate events @see https://developers.facebook.com/docs/marketing-api/conversions-api/deduplicate-pixel-and-server-events/
4399                var args = {};
4400                if(options.facebook.serverApiEnabled && event.hasOwnProperty('eventID')) {
4401                    args.eventID = event.eventID;
4402                }
4403                Facebook.maybeInitPixel(pixelId);
4404                fbq(actionType,pixelId, name, params,args);
4405            });
4406            var customEvent = new CustomEvent('facebook_event_sent', {
4407                detail: {
4408                    eventName: name,
4409                    params: params,
4410                    pixel_ids: ids
4411                }
4412            });
4413            window.dispatchEvent(customEvent);
4414        }
4415
4416        /**
4417         * Public API
4418         */
4419        return {
4420            tag: function() {
4421                return "facebook";
4422            },
4423            isEnabled: function () {
4424                return options.hasOwnProperty('facebook');
4425            },
4426            getHidePixel: function(){
4427                if(this.isEnabled() && options.facebook.hasOwnProperty('hide_pixels'))
4428                {
4429                    return options.facebook.hide_pixels;
4430                }
4431                return [];
4432            },
4433            initEventIdCookies: function (key) {
4434                var ids = {};
4435                ids[key] = pys_generate_token(36)
4436                Cookies.set('pys_fb_event_id', JSON.stringify(ids), {path: '/',domain: domain});
4437            },
4438
4439            updateEventId:function(key) {
4440                var cooData = Cookies.get("pys_fb_event_id")
4441                if(cooData === undefined) {
4442                    this.initEventIdCookies(key);
4443                } else {
4444                    var data = JSON.parse(cooData);
4445                    data[key] = pys_generate_token(36);
4446                    Cookies.set('pys_fb_event_id', JSON.stringify(data), {path: '/',domain: domain} );
4447                }
4448            },
4449
4450            getEventId:function (key) {
4451                var data = Cookies.get("pys_fb_event_id");
4452                if(data === undefined) {
4453                    this.initEventIdCookies(key);
4454                    data = Cookies.get("pys_fb_event_id");
4455                }
4456                return JSON.parse(data)[key];
4457            },
4458
4459            disable: function () {
4460                initialized = false;
4461            },
4462
4463            filterParams: function (params) {
4464                var filteredParams = {};
4465
4466                if (options.facebook.hasOwnProperty('enabled_medical') && options.facebook.enabled_medical && options.facebook.hasOwnProperty('do_not_track_medical_param')) {
4467                    // Remove empty strings from the array
4468                    options.facebook.do_not_track_medical_param = options.facebook.do_not_track_medical_param.filter(Boolean);
4469                    for (const key in params) {
4470                        if (Array.isArray(options.facebook.do_not_track_medical_param)) {
4471                            if (!options.facebook.do_not_track_medical_param.includes(key)) {
4472                                filteredParams[key] = params[key];
4473                            }
4474                        }
4475                    }
4476                }
4477                else {
4478                    Utils.copyProperties(params, filteredParams);
4479                }
4480                return filteredParams;
4481            },
4482
4483            /**
4484             * Load pixel's JS
4485             */
4486            loadPixel: function () {
4487                if (initialized || !this.isEnabled() || !Utils.consentGiven('facebook')) {
4488                    return;
4489                }
4490
4491                ! function (f, b, e, v, n, t, s) {
4492                    if (f.fbq) return;
4493                    n = f.fbq = function () {
4494                        n.callMethod ?
4495                            n.callMethod.apply(n, arguments) : n.queue.push(arguments)
4496                    };
4497                    if (!f._fbq) f._fbq = n;
4498                    n.push = n;
4499                    n.loaded = !0;
4500                    n.version = '2.0';
4501                    n.agent = 'dvpixelyoursite';
4502                    n.queue = [];
4503                    t = b.createElement(e);
4504                    t.async = !0;
4505                    t.src = v;
4506                    s = b.getElementsByTagName(e)[0];
4507                    s.parentNode.insertBefore(t, s)
4508                }(window,
4509                    document, 'script', 'https://connect.facebook.net/en_US/fbevents.js');
4510                let expires = parseInt(options.cookie_duration);
4511                if(!Cookies.get('_fbp')) {
4512                    Cookies.set('_fbp',genereateFbp(),  { expires: expires,path: '/',domain: domain });
4513                }
4514
4515                if(getUrlParameter('fbclid')) {
4516                    Cookies.set('_fbc',genereateFbc(),  { expires: expires,path: '/',domain: domain });
4517                }
4518                var ids = options.facebook.pixelIds.filter(function (pixelId) {
4519                    return !Utils.hideMatchingPixel(pixelId, 'facebook');
4520                });
4521                // initialize default pixel
4522                ids.forEach(function (pixelId) {
4523                    Facebook.maybeInitPixel(pixelId);
4524                });
4525                initialized = true;
4526
4527                Utils.fireStaticEvents('facebook');
4528
4529            },
4530            advancedMatching: function () {
4531                if(options.facebook.advancedMatchingEnabled) {
4532                    let advancedMatchingForm = Utils.getAdvancedFormData();
4533                    let advancedMatching = {};
4534                    if(Object.keys(options.facebook.advancedMatching).length > 0) {
4535                        advancedMatching = options.facebook.advancedMatching;
4536                    }
4537
4538                    if(!advancedMatching.hasOwnProperty("em")
4539                        && advancedMatchingForm.hasOwnProperty("email") && advancedMatchingForm["email"].length > 0) {
4540                        advancedMatching["em"] = advancedMatchingForm["email"];
4541                    }
4542                    if(!advancedMatching.hasOwnProperty("ph")
4543                        && advancedMatchingForm.hasOwnProperty("phone") && advancedMatchingForm["phone"].length > 0) {
4544                        advancedMatching["ph"] = advancedMatchingForm["phone"];
4545                    }
4546                    if(!advancedMatching.hasOwnProperty("fn")
4547                        && advancedMatchingForm.hasOwnProperty("first_name") && advancedMatchingForm["first_name"].length > 0) {
4548                        advancedMatching["fn"] = advancedMatchingForm["first_name"];
4549                    }
4550                    if(!advancedMatching.hasOwnProperty("ln")
4551                        && advancedMatchingForm.hasOwnProperty("last_name") && advancedMatchingForm["last_name"].length > 0) {
4552                        advancedMatching["ln"] = advancedMatchingForm["last_name"];
4553                    }
4554                    if(!advancedMatching.hasOwnProperty("external_id")){
4555                        if (Cookies.get('pbid')) {
4556                            advancedMatching["external_id"] = Cookies.get('pbid');
4557                        }
4558                    }
4559                    else if(advancedMatching.hasOwnProperty("external_id") && advancedMatching.external_id != Cookies.get('pbid'))
4560                    {
4561                        advancedMatching["external_id"] = Cookies.get('pbid') ? Cookies.get('pbid') : advancedMatching.external_id;
4562                    }
4563
4564                    if(Object.keys(advancedMatching).length > 0) {
4565                        return advancedMatching;
4566                    }
4567                }
4568                return false
4569            },
4570            maybeInitPixel: function(pixelId) {
4571
4572                if(configuredPixels.includes(pixelId)) return;
4573
4574                if (options.facebook.removeMetadata || Utils.hideMatchingPixel(pixelId, this.tag())) {
4575                    fbq('set', 'autoConfig', false, pixelId);
4576                }
4577                let advancedMatching = Facebook.advancedMatching();
4578
4579                if ( +options.facebook.meta_ldu === 1  ) {
4580                    fbq( 'dataProcessingOptions', [ 'LDU' ], 0, 0 );
4581                }
4582
4583                if (options.gdpr.consent_magic_integration_enabled && typeof CS_Data !== "undefined") {
4584                    if(!advancedMatching) {
4585                        fbq('init', pixelId);
4586                    } else {
4587                        var test_prefix = CS_Data.test_prefix;
4588                        var cs_advanced_matching = Cookies.get('cs_enabled_advanced_matching'+test_prefix);
4589                        if (jQuery('#cs_enabled_advanced_matching'+test_prefix).length > 0) {
4590                            if (cs_advanced_matching == 'yes') {
4591                                fbq('init', pixelId, advancedMatching);
4592                            } else {
4593                                fbq('init', pixelId);
4594                            }
4595                        } else {
4596                            fbq('init', pixelId, advancedMatching);
4597                        }
4598                    }
4599                } else {
4600                    if(!advancedMatching) {
4601                        fbq('init', pixelId);
4602                    }  else {
4603                        fbq('init', pixelId, advancedMatching);
4604                    }
4605                }
4606                configuredPixels.push(pixelId);
4607            },
4608
4609            fireEvent: function (name, data) {
4610
4611                if (!initialized || !this.isEnabled()) {
4612                    return false;
4613                }
4614
4615                data.delay = data.delay || 0;
4616                data.params = data.params || {};
4617
4618                if (data.delay === 0) {
4619
4620                    fireEvent(name, data);
4621
4622                } else {
4623
4624                    setTimeout(function (name, params) {
4625                        fireEvent(name, params);
4626                    }, data.delay * 1000, name, data);
4627
4628                }
4629
4630                return true;
4631
4632            },
4633
4634            onAdSenseEvent: function (event) {
4635                this.fireEvent(event.name, event);
4636            },
4637
4638            onClickEvent: function (event) {
4639                this.fireEvent(event.name, event);
4640            },
4641
4642            onWatchVideo: function (event) {
4643                this.fireEvent(event.name, event);
4644            },
4645
4646            onCommentEvent: function (event) {
4647                this.fireEvent(event.name, event);
4648            },
4649
4650            onFormEvent: function (event) {
4651                this.fireEvent(event.name, event);
4652            },
4653
4654            onDownloadEvent: function (event) {
4655                this.fireEvent(event.name, event);
4656
4657            },
4658
4659
4660            onWooAddToCartOnButtonEvent: function (product_id) {
4661
4662                window.pysWooProductData = window.pysWooProductData || [];
4663                if(!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
4664                    return;
4665
4666                if (window.pysWooProductData.hasOwnProperty(product_id)) {
4667                    if (window.pysWooProductData[product_id].hasOwnProperty('facebook')) {
4668
4669                        var event = Utils.clone(options.dynamicEvents.woo_add_to_cart_on_button_click[this.tag()])
4670
4671                        Utils.copyProperties(window.pysWooProductData[product_id]['facebook']['params'], event.params)
4672                        event.pixelIds = window.pysWooProductData[product_id]['facebook']['pixelIds'];
4673                        this.fireEvent(event.name, event);
4674                    }
4675                }
4676            },
4677
4678            onWooAddToCartOnSingleEvent: function (product_id, qty, product_type, is_external, $form) {
4679
4680                window.pysWooProductData = window.pysWooProductData || [];
4681                if(!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
4682                    return;
4683
4684                if (product_type === Utils.PRODUCT_VARIABLE && !options.facebook.wooVariableAsSimple) {
4685                    product_id = parseInt($form.find('input[name="variation_id"]').val());
4686                }
4687
4688                if (window.pysWooProductData.hasOwnProperty(product_id)) {
4689                    if (window.pysWooProductData[product_id].hasOwnProperty('facebook')) {
4690
4691                        var event = Utils.clone(options.dynamicEvents.woo_add_to_cart_on_button_click.facebook);
4692
4693
4694                        Utils.copyProperties(window.pysWooProductData[product_id]['facebook']['params'], event.params);
4695
4696                        var groupValue = 0;
4697                        if(product_type === Utils.PRODUCT_GROUPED ) {
4698                            $form.find(".woocommerce-grouped-product-list .qty").each(function(index){
4699                                var childId = $(this).attr('name').replaceAll("quantity[","").replaceAll("]","");
4700                                var quantity = parseInt($(this).val());
4701                                if(isNaN(quantity)) {
4702                                    quantity = 0;
4703                                }
4704                                var childItem = window.pysWooProductData[product_id]['facebook'].grouped[childId];
4705
4706                                if(quantity == 0) {
4707                                    event.params.content_ids.forEach(function(el,index,array) {
4708                                        if(el == childItem.content_id) {
4709                                            array.splice(index, 1);
4710                                        }
4711                                    });
4712                                }
4713
4714                                if(event.params.hasOwnProperty('contents')) {
4715                                    event.params.contents.forEac
4715h(function(el,index,array) {
4716                                        if(el.id == childItem.content_id) {
4717                                            if(quantity > 0){
4718                                                el.quantity = quantity;
4719                                            } else {
4720                                                array.splice(index, 1);
4721                                            }
4722                                        }
4723                                    });
4724                                }
4725
4726
4727                                groupValue += childItem.price * quantity;
4728                            });
4729                            if(groupValue == 0) return; // skip if no items selected
4730                        }
4731
4732
4733
4734                        // maybe customize value option
4735                        if (options.woo.addToCartOnButtonValueEnabled && options.woo.addToCartOnButtonValueOption !== 'global') {
4736
4737                            if(product_type === Utils.PRODUCT_GROUPED) {
4738                                event.params.value = groupValue;
4739                            } else if(product_type === Utils.PRODUCT_BUNDLE) {
4740                                var data = $(".bundle_form .bundle_data").data("bundle_form_data");
4741                                var items_sum = getBundlePriceOnSingleProduct(data);
4742                                event.params.value = (parseFloat(data.base_price) + items_sum )* qty;
4743                            } else {
4744                                event.params.value = event.params.value * qty;
4745                            }
4746                        }
4747
4748                        // only when non Facebook for WooCommerce logic used
4749                        if (event.params.hasOwnProperty('contents') && product_type !== Utils.PRODUCT_GROUPED) {
4750                            event.params.contents[0].quantity = qty;
4751
4752                        }
4753
4754                        var event_name = is_external ? options.woo.affiliateEventName : event.name;
4755
4756                        this.fireEvent(event_name, event);
4757
4758                    }
4759                }
4760
4761            },
4762
4763            onWooRemoveFromCartEvent: function (event) {
4764                this.fireEvent(event.name, event);
4765            },
4766
4767            onWooAffiliateEvent: function (product_id) {
4768                if(!options.dynamicEvents.woo_affiliate.hasOwnProperty(this.tag()))
4769                    return;
4770                var event = Utils.clone(options.dynamicEvents.woo_affiliate[this.tag()]);
4771
4772
4773                if (window.pysWooProductData.hasOwnProperty(product_id)) {
4774                    if (window.pysWooProductData[product_id].hasOwnProperty('facebook')) {
4775
4776                        Utils.copyProperties(window.pysWooProductData[product_id][this.tag()].params, event.params)
4777                        this.fireEvent(options.woo.affiliateEventName, event);
4778
4779                    }
4780                }
4781
4782            },
4783
4784            onWooPayPalEvent: function (event) {
4785                this.fireEvent(event.name, event);
4786            },
4787
4788            onEddAddToCartOnButtonEvent: function (download_id, price_index, qty) {
4789                if(!options.dynamicEvents.edd_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
4790                    return;
4791                var event = Utils.clone(options.dynamicEvents.edd_add_to_cart_on_button_click[this.tag()]);
4792
4793                if (window.pysEddProductData.hasOwnProperty(download_id)) {
4794
4795                    var index;
4796
4797                    if (price_index) {
4798                        index = download_id + '_' + price_index;
4799                    } else {
4800                        index = download_id;
4801                    }
4802
4803                    if (window.pysEddProductData[download_id].hasOwnProperty(index)) {
4804                        if (window.pysEddProductData[download_id][index].hasOwnProperty('facebook')) {
4805
4806                            Utils.copyProperties(window.pysEddProductData[download_id][index]['facebook']["params"], event.params)
4807
4808                            // maybe customize value option
4809                            if (options.edd.addToCartOnButtonValueEnabled && options.edd.addToCartOnButtonValueOption !== 'global') {
4810                                event.params.value = event.params.value * qty;
4811                            }
4812
4813                            // update contents qty param
4814                            var contents = event.params.contents;
4815                            contents[0].quantity = qty;
4816                            event.params.contents = contents;
4817
4818                            this.fireEvent(event.name,event);
4819
4820                        }
4821                    }
4822
4823                }
4824
4825            },
4826
4827            onEddRemoveFromCartEvent: function (event) {
4828                this.fireEvent(event.name, event);
4829            },
4830            onPageScroll: function (event) {
4831                this.fireEvent(event.name, event);
4832            },
4833            onTime: function (event) {
4834                this.fireEvent(event.name, event);
4835            },
4836        };
4837
4838    }(options);
4839
4840    var Analytics = function (options) {
4841
4842        var initialized = false;
4843        var isAllowEnhancedConversions = false;
4844
4845        /**
4846         * Fires event
4847         *
4848         * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/sending-data
4849         * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/events
4850         * @link: https://developers.google.com/gtagjs/reference/event
4851         * @link: https://developers.google.com/gtagjs/reference/parameter
4852         *
4853         * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/custom-dim
4853s-mets
4854         *
4855         * @param name
4856         * @param data
4857         */
4858        function fireEvent(name, event) {
4859            if(typeof window.pys_event_data_filter === "function" && window.pys_disable_event_filter(name,'ga')) {
4860                return;
4861            }
4862
4863            var eventParams = event.params;
4864            var valuesArray = Object.values(event.trackingIds);
4865            var ids = valuesArray.filter(function (pixelId) {
4866                return loadTags.some(loadTag => pixelId.startsWith(loadTag)) && !Utils.hideMatchingPixel(pixelId, 'ga') && !Utils.hideMatchingPixel(pixelId, 'google_ads');
4867            })
4868
4869            // Generate unique event_id for deduplication
4870            eventParams.event_id = Utils.generateUniqueId(event);
4871            event.eventID = Utils.generateUniqueId(event);
4872
4873            Utils.copyProperties(Utils.getRequestParams(), eventParams);
4874
4875            var copyParams = Utils.copyProperties(eventParams, {}); // copy params because mapParamsTov4 can modify 
4875it
4876            var params = mapParamsTov4(ids,name,copyParams)
4877
4878            var _fireEvent = function (tracking_ids,name,params) {
4879
4880                params['send_to'] = tracking_ids;
4881
4882                if (options.debug) {
4883                    console.log('[Google Analytics #' + tracking_ids + '] ' + name, params);
4884                }
4885
4886                // Send via gtag
4887                gtag('event', name, params);
4888
4889                var customEvent = new CustomEvent('gtag_event_sent', {
4890                    detail: {
4891                        eventName: name,
4892                        params: params,
4893                        pixel_ids: tracking_ids
4894                    }
4895                });
4896                window.dispatchEvent(customEvent);
4897            };
4898
4899
4900            delete params.analytics_storage;
4901            delete params.ad_storage;
4902            delete params.ad_user_data;
4903            delete params.ad_personalization;
4904
4905            if(options.hasOwnProperty('google_ads')){
4906                var conversion_event_name = event.e_id;
4907                switch ( conversion_event_name ) {
4908                    case "woo_add_to_cart_on_cart_page":
4909                    case "woo_add_to_cart_on_checkout_page":
4910                    case "woo_add_to_cart_on_button_click":
4911                        conversion_event_name = 'woo_add_to_cart';
4912                        break;
4913                    case "edd_add_to_cart_on_cart_page":
4914                    case "edd_add_to_cart_on_checkout_page":
4915                    case "edd_add_to_cart_on_button_click":
4916                        conversion_event_name = 'edd_add_to_cart';
4917                        break;
4918                    case "automatic_event_adsense":
4919                    case "automatic_event_comment":
4920                    case "automatic_event_download":
4921                    case "automatic_event_email_link":
4922                    case "automatic_event_form":
4923                    case "automatic_event_internal_link":
4924                    case "automatic_event_outbound_link":
4925                    case "automatic_event_scroll":
4926                    case "automatic_event_tel_link":
4927                    case "automatic_event_time_on_page":
4928                    case "automatic_event_video":
4929                        conversion_event_name = 'automatic_event';
4930                        break;
4931                }
4932
4933                if (conversion_event_name !== 'automatic_event') {
4934                    // We replace the event name for the settings key if it is woo_view_item_list
4935                    const trackEventName = conversion_event_name === 'woo_view_item_list'
4936                        ? 'woo_view_category'
4937                        : conversion_event_name;
4938
4939                    if (typeof options.google_ads[trackEventName + '_conversion_track'] !== 'undefined') {
4940                        const conversionTrack = options.google_ads[trackEventName + '_conversion_track'];
4941
4942                        if (conversionTrack === 'conversion') {
4943                            ids = ids.map(id => id.split('/')[0]);
4944                        }
4945                    }
4946                }
4947            }
4948
4949
4950            _fireEvent(ids, name, params);
4951            if(event.hasOwnProperty('unify') && event.unify){
4952                isTrackEventForGA.push(name);
4953            }
4954        }
4955
4956        function normalizeEventName(eventName) {
4957
4958            var matches = {
4959                ViewContent: 'view_item',
4960                AddToCart: 'add_to_cart',
4961                AddToWishList: 'add_to_wishlist',
4962                InitiateCheckout: 'begin_checkout',
4963                Purchase: 'purchase',
4964                Lead: 'generate_lead',
4965                CompleteRegistration: 'sign_up',
4966                AddPaymentInfo: 'set_checkout_option'
4967            };
4968
4969            return matches.hasOwnProperty(eventName) ? matches[eventName] : eventName;
4970
4971        }
4972
4973        function mapParamsTov4(tag,name,param) {
4974            //GA4 automatically collects a number of parameters for all events
4975            var hasGA4Tag = false;
4976
4977            // end
4978            if (Array.isArray(tag)) {
4979                hasGA4Tag = tag.some(function (element) {
4980                    return isv4(element);
4981                });
4982            } else if(isv4(tag)) {
4983                // tag is a string and matches GA4
4984                hasGA4Tag = true;
4985            }
4986            if(hasGA4Tag) {
4987                delete param.event_category;
4988                delete param.event_label;
4989                delete param.ecomm_prodid;
4990                delete param.ecomm_pagetype;
4991                delete param.ecomm_totalvalue;
4992                if(name === 'search') {
4993                    param['search'] = param.search_term;
4994                    delete param.search_term;
4995                    delete param.dynx_itemid;
4996                    delete param.dynx_pagetype;
4997                    delete param.dynx_totalvalue;
4998                }
4999            }
5000            return param;
5001        }
5002
5003        function isv4(tag) {
5004            return tag.indexOf('G') === 0;
5005        }
5006
5007        /**
5008         * Public API
5009         */
5010        return {
5011            tag: function() {
5012                return "ga";
5013            },
5014            isEnabled: function () {
5015                return options.hasOwnProperty('ga');
5016            },
5017            getHidePixel: function(){
5018                if(this.isEnabled() && options.ga.hasOwnProperty('hide_pixels'))
5019                {
5020                    return options.ga.hide_pixels;
5021                }
5022                return [];
5023            },
5024            disable: function () {
5025                initialized = false;
5026            },
5027            updateEnhancedConversionData : function () {
5028                if (!initialized || !this.isEnabled()) {
5029                    return;
5030                }
5031                if(options.hasOwnProperty("tracking_analytics") && options.tracking_analytics.hasOwnProperty("userDataEnable") && options.tracking_analytics.userDataEnable) {
5032                    var advanced = Utils.getAdvancedMergeFormData();
5033                    if (Object.keys(advanced).length > 0) {
5034                        gtag('set', 'user_data', advanced);
5035                    }
5036                }
5037            },
5038            loadPixel: function () {
5039                if (initialized || !this.isEnabled() || !Utils.consentGiven('analytics')) {
5040                    return;
5041                }
5042
5043
5044                for (var i = 0; i < options.ga.trackingIds.length; i++) {
5045                    var trackingId = options.ga.trackingIds[i];
5046                    if (!Utils.hideMatchingPixel(trackingId, 'ga')) {
5047                        Utils.loadGoogleTag(trackingId);
5048                        break;
5049                    }
5050                }
5051
5052
5053                if(options.hasOwnProperty("tracking_analytics") && options.tracking_analytics.hasOwnProperty("userDataEnable") && options.tracking_analytics.userDataEnable){
5054                    var advanced = Utils.getAdvancedMergeFormData();
5055                    if(Object.keys(advanced).length > 0){
5056                        gtag('set', 'user_data', advanced);
5057                    }
5058                }
5059
5060                var config = {};
5061
5062                if(options.user_id && options.user_id != 0) {
5063                    config.user_id = options.user_id;
5064                }
5065                config.url_passthrough = options.ga.url_passthrough;
5066                // Cross-Domain tracking
5067                if (options.ga.crossDomainEnabled) {
5068                    config.linker = {
5069                        accept_incoming: options.ga.crossDomainAcceptIncoming,
5070                        domains: options.ga.crossDomainDomains
5071                    };
5072                }
5073
5074                var ids = options.ga.trackingIds.filter(function (pixelId) {
5075                    return !Utils.hideMatchingPixel(pixelId, 'ga');
5076                });
5077                loadTags.push(...ids);
5078                ids.forEach(function (trackingId,index) {
5079
5080                    var obj = options.ga.isDebugEnabled;
5081                    var searchValue = "index_"+index;
5082                    var config_for_tag = Object.assign({}, config);
5083                    config_for_tag.debug_mode = false;
5084                    config_for_tag.send_page_view = !options.ga.custom_page_view_event;
5085                    for (var key in obj) {
5086                        if (obj[key] === searchValue) {
5087                            config_for_tag.debug_mode = true;
5088                            break;
5089                        }
5090                    }
5091                    if(!config_for_tag.debug_mode)
5092                    {
5093                        delete config_for_tag.debug_mode;
5094                    }
5095
5096                    if(isv4(trackingId)) {
5097                        if(options.ga.disableAdvertisingPersonalization) {
5098                            config_for_tag.allow_ad_personalization_signals = false
5099                        }
5100                    }
5101                    if(options.ga.hasOwnProperty('additionalConfig')){
5102                        if(options.ga.additionalConfig.hasOwnProperty(trackingId) && options.ga.additionalConfig[trackingId]){
5103                            config_for_tag.first_party_collection = options.ga.additionalConfig[trackingId].first_party_collection;
5104                        }
5105
5106                    }
5107                    if(options.ga.hasOwnProperty('serverContainerUrls')){
5108                        if(options.ga.serverContainerUrls.hasOwnProperty(trackingId) && options.ga.serverContainerUrls[trackingId].enable_server_container != false){
5109                            if(options.ga.serverContainerUrls[trackingId].server_container_url != ''){
5110                                config_for_tag.server_container_url = options.ga.serverContainerUrls[trackingId].server_container_url;
5111                            }
5112                            if(options.ga.serverContainerUrls[trackingId].transport_url != ''){
5113                                config_for_tag.transport_url = options.ga.serverContainerUrls[trackingId].transport_url;
5114                            }
5115                        }
5116                    }
5117                    if (options.gdpr.cookiebot_integration_enabled && typeof Cookiebot !== 'undefined') {
5118                        var cookiebot_consent_category = options.gdpr['cookiebot_analytics_consent_category'];
5119                        if (options.gdpr['analytics_prior_consent_enabled']) {
5120                            if (Cookiebot.consented === true && Cookiebot.consent[cookiebot_consent_category]) {
5121                                gtag('config', trackingId, config_for_tag);
5122                            }
5123                        } else {
5124                            if (Cookiebot.consent[cookiebot_consent_category]) {
5125                                gtag('config', trackingId, config_for_tag);
5126                            }
5127                        }
5128                    }
5129                    else
5130                    {
5131                        gtag('config', trackingId, config_for_tag);
5132                    }
5133                });
5134                if(!isAdsLoad && GAds.isEnabled() && options.google_ads.conversion_ids.length > 0 && Utils.consentGiven('google_ads')) {
5135                    for (var i = 0; i < options.google_ads.conversion_ids.length; i++) {
5136                        var trackingId = options.google_ads.conversion_ids[i];
5137                        if (!Utils.hideMatchingPixel(trackingId, 'google_ads')) {
5138                            Utils.loadGoogleTag(trackingId);
5139                            break;
5140                        }
5141                    }
5142                    var ids = options.google_ads.conversion_ids.filter(function (pixelId) {
5143                        return !Utils.hideMatchingPixel(pixelId, 'google_ads');
5144                    });
5145                    loadTags.push(...ids);
5146                    // configure conversion ids
5147                    ids.forEach(function (conversion_id,index) {
5148
5149                        gtag('config', conversion_id);
5150
5151                        if(options.google_ads.enhanced_conversion.includes("index_"+index)) {
5152                            isAllowEnhancedConversions = true
5153                            gtag('config', conversion_id,{ 'allow_enhanced_conversions':true });
5154                        }
5155
5156	                    Utils.registerGadsPhoneConversion( conversion_id );
5157
5158                    });
5159                    isAdsLoad = true;
5160                }
5161
5162                initialized = true;
5163
5164                Utils.fireStaticEvents('ga');
5165                $( document).trigger( "analytics_initialized")
5166            },
5167
5168            fireEvent: function (name, data) {
5169
5170                if (!initialized || !this.isEnabled()) {
5171                    return false;
5172                }
5173
5174                data.delay = data.delay || 0;
5175                data.params = data.params || {};
5176
5177                if (data.delay === 0) {
5178
5179                    fireEvent(name, data);
5180
5181                } else {
5182
5183                    setTimeout(function (name, params) {
5184                        fireEvent(name, params);
5185                    }, data.delay * 1000, name, data);
5186
5187                }
5188
5189                return true;
5190
5191            },
5192
5193            onAdSenseEvent: function (event) {
5194                this.fireEvent(event.name, event);
5195            },
5196
5197            onClickEvent: function (event) {
5198                this.fireEvent(event.name, event);
5199            },
5200
5201            onWatchVideo: function (event) {
5202                if(!event.hasOwnProperty("youtube_disabled")
5203                    || !event.youtube_disabled
5204                    || event.params.video_type !== "youtube") {
5205                    this.fireEvent(event.name, event);
5206                }
5207            },
5208
5209            onCommentEvent: function (event) {
5210
5211                this.fireEvent(event.name, event);
5212
5213            },
5214
5215            onFormEvent: function (event) {
5216
5217                this.fireEvent(event.name, event);
5218
5219            },
5220
5221            onDownloadEvent: function (event) {
5222
5223                this.fireEvent(event.name, event);
5224
5225            },
5226
5227            onWooAddToCartOnButtonEvent: function (product_id, prod_info = null) {
5228                if(!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
5229                    return;
5230
5231                if (window.pysWooProductData.hasOwnProperty(product_id)) {
5232                    if (window.pysWooProductData[product_id].hasOwnProperty('ga')) {
5233                        var event = Utils.clone(options.dynamicEvents.woo_add_to_cart_on_button_click[this.tag()]);
5234                        Utils.copyProperties(window.pysWooProductData[product_id]['ga'].params, event.params)
5235                        event.trackingIds = window.pysWooProductData[product_id]['ga']['trackingIds'];
5236                        if(prod_info)
5237                        {
5238                            if(prod_info['pys_list_name_productlist_id'])
5239                            {
5240                                event.params.items[0]['item_list_id'] = prod_info['pys_list_name_productlist_id']
5241                            }
5242                            if(prod_info['pys_list_name_productlist_name'])
5243                            {
5244                                event.params.items[0]['item_list_name'] =prod_info['pys_list_name_productlist_name']
5245                            }
5246                        }
5247                        this.fireEvent(event.name, event);
5248                    }
5249                }
5250
5251            },
5252
5253            onWooAddToCartOnSingleEvent: function (product_id, qty, product_type, is_external, $form, prod_info) {
5254
5255                window.pysWooProductData = window.pysWooProductData || [];
5256
5257                if(!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
5258                    return;
5259                var event = Utils.clone(options.dynamicEvents.woo_add_to_cart_on_button_click[this.tag()]);
5260
5261                if (product_type === Utils.PRODUCT_VARIABLE && !options.ga.wooVariableAsSimple) {
5262                    product_id = parseInt($form.find('input[name="variation_id"]').val());
5263                }
5264
5265                if (window.pysWooProductData.hasOwnProperty(product_id)) {
5266                    if (window.pysWooProductData[product_id].hasOwnProperty('ga')) {
5267
5268                        Utils.copyProperties(window.pysWooProductData[product_id]['ga'].params, event.params);
5269
5270
5271                        if(product_type === Utils.PRODUCT_GROUPED ) {
5272                            var groupValue = 0;
5273                            $form.find(".woocommerce-grouped-product-list .qty").each(function(index){
5274                                var childId = $(this).attr('name').replaceAll("quantity[","").replaceAll("]","");
5275                                var quantity = parseInt($(this).val());
5276                                if(isNaN(quantity)) {
5277                                    quantity = 0;
5278                                }
5279                                var childItem = window.pysWooProductData[product_id]['ga'].grouped[childId];
5280                                event.params.items.forEach(function(el,index,array) {
5281                                    if(el.id == childItem.content_id) {
5282                                        if(quantity > 0){
5283                                            el.quantity = quantity;
5284                                            el.price = childItem.price;
5285                                        } else {
5286                                            array.splice(index, 1);
5287                                        }
5288                                    }
5289                                });
5290                                groupValue += childItem.price * quantity;
5291                            });
5292
5293                            if(options.woo.addToCartOnButtonValueEnabled &&
5294                                options.woo.addToCartOnButtonValueOption !== 'global' &&
5295                                event.params.hasOwnProperty('value')) {
5296                                event.params.value = groupValue;
5297                            }
5298
5299                            if(groupValue == 0) return; // skip if no items selected
5300                        } else {
5301                            // update items qty param
5302                            event.params.items[0].quantity = qty;
5303                        }
5304
5305                        // maybe customize value option
5306                        if (options.woo.addToCartOnButtonValueEnabled &&
5307                            options.woo.addToCartOnButtonValueOption !== 'global' &&
5308                            product_type !== Utils.PRODUCT_GROUPED)
5309                        {
5310                            if(event.params.hasOwnProperty('value')) {
5311                                event.params.value = event.params.items[0].price * qty;
5312                            }
5313                        }
5314
5315                        if(prod_info)
5316                        {
5317                            if(prod_info['pys_list_name_productlist_id'])
5318                            {
5319                                event.params.items[0]['item_list_id'] = prod_info['pys_list_name_productlist_id']
5320                            }
5321                            if(prod_info['pys_list_name_productlist_name'])
5322                            {
5323                                event.params.items[0]['item_list_name'] =prod_info['pys_list_name_productlist_name']
5324                            }
5325                        }
5326
5327                        var eventName = is_external ? options.woo.affiliateEventName : event.name;
5328                        eventName = normalizeEventName(eventName);
5329
5330                        this.fireEvent(eventName, event);
5331
5332                    }
5333                }
5334
5335            },
5336
5337            onWooCheckoutProgressStep: function (event) {
5338                this.fireEvent(event.name, event);
5339            },
5340
5341            onWooSelectContent: function (event) {
5342                const select_prod_list = {};
5343
5344                if (event.params.items[0].item_list_name !== undefined) {
5345                    select_prod_list.list_name = event.params.items[0].item_list_name;
5346                }
5347
5348                if (event.params.items[0].item_list_id !== undefined) {
5349                    select_prod_list.list_id = event.params.items[0].item_list_id;
5350                }
5351                const url = new URL(window.location.href);
5352                select_prod_list.url = url.origin + url.pathname;
5353                Cookies.set('select_prod_list', JSON.stringify(select_prod_list), { expires: 1,path: '/' });
5354                this.fireEvent(event.name, event);
5355            },
5356
5357            onWooRemoveFromCartEvent: function (event) {
5358                this.fireEvent(event.name, event);
5359            },
5360
5361            onWooAffiliateEvent: function (product_id) {
5362                if(!options.dynamicEvents.woo_affiliate.hasOwnProperty(this.tag()))
5363                    return;
5364                var event = options.dynamicEvents.woo_affiliate[this.tag()];
5365
5366                if (window.pysWooProductData.hasOwnProperty(product_id)) {
5367                    if (window.pysWooProductData[product_id].hasOwnProperty('ga')) {
5368
5369                        event = Utils.clone(event );
5370                        Utils.copyProperties(window.pysWooProductData[product_id][this.tag()], event.params)
5371                        this.fireEvent(normalizeEventName(options.woo.affiliateEventName), event);
5372
5373                    }
5374                }
5375
5376            },
5377
5378            onWooPayPalEvent: function (event) {
5379                this.fireEvent(event.name, event);
5380            },
5381
5382            onEddAddToCartOnButtonEvent: function (download_id, price_index, qty) {
5383                if(!options.dynamicEvents.edd_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
5384                    return;
5385                var event = Utils.clone(options.dynamicEvents.edd_add_to_cart_on_button_click[this.tag()]);
5386
5387
5388                if (window.pysEddProductData.hasOwnProperty(download_id)) {
5389
5390                    var index;
5391
5392                    if (price_index) {
5393                        index = download_id + '_' + price_index;
5394                    } else {
5395                        index = download_id;
5396                    }
5397
5398                    if (window.pysEddProductData[download_id].hasOwnProperty(index)) {
5399                        if (window.pysEddProductData[download_id][index].hasOwnProperty('ga')) {
5400
5401                            Utils.copyProperties(window.pysEddProductData[download_id][index]['ga'].params, event.params);
5402
5403                            // update items qty param
5404                            event.params.items[0].quantity = qty;
5405
5406                            this.fireEvent(event.name,event);
5407
5408                        }
5409                    }
5410
5411                }
5412
5413            },
5414
5415            onEddRemoveFromCartEvent: function (event) {
5416                this.fireEvent(event.name, event);
5417            },
5418
5419            onPageScroll: function (event) {
5420                if (initialized && this.isEnabled()) {
5421                    this.fireEvent(event.name, event);
5422                }
5423            },
5424            onTime: function (event) {
5425                if (initialized && this.isEnabled()) {
5426                    this.fireEvent(event.name, event);
5427                }
5428            },
5429        };
5430
5431    }(options);
5432
5433    var GAds = function (options) {
5434
5435        var initialized = false;
5436        var isAllowEnhancedConversions = false
5437        /**
5438         * Fires event
5439         *
5440         * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/sending-data
5441         * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/events
5442         * @link: https://developers.google.com/gtagjs/reference/event
5443         * @link: https://developers.google.com/gtagjs/reference/parameter
5444         */
5445        function fireEvent(name, data) {
5446            if(typeof window.pys_event_data_filter === "function" && window.pys_disable_event_filter(event_name,'google_ads')) {
5447                return;
5448            }
5449            var _params = Utils.copyProperties(data.params,{});
5450
5451            _params.event_id = Utils.generateUniqueId(data);
5452
5453            var ids = data.ids.filter(function (pixelId) {
5454                return !Utils.hideMatchingPixel(pixelId, 'google_ads');
5455            });
5456
5457            var conversionIds = data.hasOwnProperty('conversion_ids') ? data.conversion_ids.filter(function (conversion_id) {
5458                return !Utils.hideMatchingPixel(conversion_id, 'google_ads');
5459            }) : [];
5460            var conversion_labels = data.hasOwnProperty('conversion_labels') ? data.conversion_labels.filter(function (conversion_label) {
5461                conversion_id = conversion_label.split('/')[0];
5462                return !Utils.hideMatchingPixel(conversion_id, 'google_ads');
5463            }) : [];
5464
5465            Utils.copyProperties(Utils.getRequestParams(), _params);
5466            var _fireEvent = function (conversion_id,event_name) {
5467
5468                params = Utils.copyProperties(_params, { send_to: conversion_id });
5469
5470                if("conversion" === event_name) {
5471                    delete params.items;
5472                    delete params.ecomm_pagetype;
5473                    delete params.ecomm_prodid;
5474                    delete params.ecomm_totalvalue;
5475                }
5476
5477                if (options.debug) {
5478                    console.log('[Google Ads #' + conversion_id + '] ' + event_name, params);
5479                }
5480                gtag('event', event_name, params);
5481                var customEvent = new CustomEvent('gtag_event_sent', {
5482                    detail: {
5483                        eventName: event_name,
5484                        params: params,
5485                        pixel_ids: conversion_id
5486                    }
5487                });
5488                window.dispatchEvent(customEvent);
5489
5490            };
5491
5492
5493            if ( conversion_labels.length > 0 ) {
5494                ids = conversion_labels;
5495                if ( !isTrackEventForGA.includes( name ) ) {
5496                    _fireEvent( ids, name );
5497                }
5498            } else {
5499                var conversion_event_name = data.e_id;
5500                switch ( conversion_event_name ) {
5501                    case "woo_add_to_cart_on_cart_page":
5502                    case "woo_add_to_cart_on_checkout_page":
5503                    case "woo_add_to_cart_on_button_click":
5504                        conversion_event_name = 'woo_add_to_cart';
5505                        break;
5506                    case "edd_add_to_cart_on_cart_page":
5507                    case "edd_add_to_cart_on_checkout_page":
5508                    case "edd_add_to_cart_on_button_click":
5509                        conversion_event_name = 'edd_add_to_cart';
5510                        break;
5511                    case "automatic_event_adsense":
5512                    case "automatic_event_comment":
5513                    case "automatic_event_download":
5514                    case "automatic_event_email_link":
5515                    case "automatic_event_form":
5516                    case "automatic_event_internal_link":
5517                    case "automatic_event_outbound_link":
5518                    case "automatic_event_scroll":
5519                    case "automatic_event_tel_link":
5520                    case "automatic_event_time_on_page":
5521                    case "automatic_event_video":
5522                        conversion_event_name = 'automatic_event';
5523                        break;
5524                }
5525
5526                if (ids.length) {
5527                    if (conversion_event_name !== 'automatic_event' && options.hasOwnProperty('google_ads')) {
5528                        // In the same way, we determine the correct name for the settings key.
5529                        const trackEventName = conversion_event_name === 'woo_view_item_list'
5530                            ? 'woo_view_category'
5531                            : conversion_event_name;
5532
5533                        const conversionTrack = options.google_ads[trackEventName + '_conversion_track'];
5534
5535                        if (conversionTrack === 'conversion') {
5536                            _fireEvent(ids, "conversion");
5537                            ids = conversionIds;
5538                        }
5539                    }
5540                } else {
5541                    ids = conversionIds;
5542                }
5543
5544                if ( !isTrackEventForGA.includes( name ) ) {
5545                    _fireEvent( ids, name );
5546                }
5547            }
5548        }
5549
5550        function normalizeEventName(eventName) {
5551
5552            var matches = {
5553                ViewContent: 'view_item',
5554                AddToCart: 'add_to_cart',
5555                AddToWishList: 'add_to_wishlist',
5556                InitiateCheckout: 'begin_checkout',
5557                Purchase: 'purchase',
5558                Lead: 'generate_lead',
5559                CompleteRegistration: 'sign_up',
5560                AddPaymentInfo: 'set_checkout_option'
5561            };
5562
5563            return matches.hasOwnProperty(eventName) ? matches[eventName] : eventName;
5564
5565        }
5566
5567        /**
5568         * Public API
5569         */
5570        return {
5571            tag: function() {
5572                return "google_ads";
5573            },
5574            isEnabled: function () {
5575                return options.hasOwnProperty('google_ads');
5576            },
5577            getHidePixel: function(){
5578                if(this.isEnabled() && options.google_ads.hasOwnProperty('hide_pixels'))
5579                {
5580                    return options.google_ads.hide_pixels;
5581                }
5582                return [];
5583            },
5584            disable: function () {
5585                initialized = false;
5586            },
5587
5588            updateEnhancedConversionData : function () {
5589
5590                if(options.hasOwnProperty("tracking_analytics") && options.tracking_analytics.hasOwnProperty("userDataEnable") && options.tracking_analytics.userDataEnable){
5591                    var advanced = Utils.getAdvancedMergeFormData()
5592                    gtag('set', 'user_data', advanced);
5593                }
5594            },
5595
5596            loadPixel: function () {
5597
5598                if (initialized || !this.isEnabled() || !Utils.consentGiven('google_ads')) {
5599                    return;
5600                }
5601                var ids = options.google_ads.conversion_ids.filter(function (pixelId) {
5602                    return !Utils.hideMatchingPixel(pixelId, 'google_ads');
5603                });
5604                loadTags.push(...ids);
5605                if(!isAdsLoad && options.google_ads.conversion_ids.length > 0){
5606                    for (var i = 0; i < options.google_ads.conversion_ids.length; i++) {
5607                        var trackingId = options.google_ads.conversion_ids[i];
5608                        if (!Utils.hideMatchingPixel(trackingId, 'google_ads')) {
5609                            Utils.loadGoogleTag(trackingId);
5610                            break;
5611                        }
5612                    }
5613
5614                    // configure conversion ids
5615                    ids.forEach(function (conversion_id,index) {
5616
5617                        let config = {};
5618
5619                        if(options.google_ads.enhanced_conversion.includes("index_"+index)) {
5620                            isAllowEnhancedConversions = true;
5621                            config.allow_enhanced_conversions = true
5622                        }
5623
5624                        // Cross-Domain tracking
5625                        if (options.google_ads.crossDomainEnabled) {
5626                            config.linker = {
5627                                accept_incoming: options.google_ads.crossDomainAcceptIncoming,
5628                                domains: options.google_ads.crossDomainDomains
5629                            };
5630                        }
5631
5632                        gtag('config', conversion_id, config );
5633
5634	                    Utils.registerGadsPhoneConversion( conversion_id );
5635
5636                        if(options.hasOwnProperty("tracking_analytics") && options.tracking_analytics.hasOwnProperty("userDataEnable") && options.tracking_analytics.userDataEnableuserDataEnable){
5637                            var advanced = Utils.getAdvancedMergeFormData()
5638                            gtag('set', 'user_data', advanced);
5639                        }
5640
5641                    });
5642                    isAdsLoad = true;
5643                }
5644
5645                initialized = true;
5646
5647                Utils.fireStaticEvents('google_ads');
5648
5649            },
5650
5651            fireEvent: function (name, data) {
5652
5653                if (!initialized || !this.isEnabled()) {
5654                    return false;
5655                }
5656
5657                data.delay = data.delay || 0;
5658                data.params = data.params || {};
5659                data.ids = data.ids || [];
5660                data.conversion_labels = data.conversion_labels || [];
5661
5662                if (data.delay === 0) {
5663                    fireEvent(name, data);
5664                } else {
5665                    setTimeout(function (name, data) {
5666                        fireEvent(name, data);
5667                    }, data.delay * 1000, name, data);
5668                }
5669
5670                return true;
5671
5672            },
5673
5674            onAdSenseEvent: function (event) {
5675                this.fireEvent(event.name, event);
5676            },
5677
5678            onClickEvent: function (action, params) {
5679                //disabled
5680            },
5681
5682            onWatchVideo: function (event) {
5683                this.fireEvent(event.name, event);
5684            },
5685
5686            onCommentEvent: function (event) {
5687                this.fireEvent(event.name, event);
5688            },
5689
5690            onFormEvent: function (event) {
5691                this.fireEvent(event.name, event);
5692            },
5693
5694            onDownloadEvent: function (event) {
5695                this.fireEvent(event.name, event);
5696            },
5697
5698
5699
5700
5701            onWooAddToCartOnButtonEvent: function (product_id) {
5702
5703                if(!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
5704                    return;
5705
5706                if (window.pysWooProductData.hasOwnProperty(product_id)) {
5707                    if (window.pysWooProductData[product_id].hasOwnProperty('google_ads')) {
5708
5709                        var event = Utils.clone(options.dynamicEvents.woo_add_to_cart_on_button_click[this.tag()])
5710                        Utils.copyProperties(window.pysWooProductData[product_id]['google_ads']['params'].params, event.params)
5711                        event["ids"] = window.pysWooProductData[product_id]['google_ads']['ids']
5712                        event["conversion_labels"] = window.pysWooProductData[product_id]['google_ads']['conversion_labels']
5713                        this.fireEvent(event.name, event);
5714                    }
5715                }
5716
5717            },
5718
5719            onWooAddToCartOnSingleEvent: function (product_id, qty, product_type, is_external, $form) {
5720
5721                window.pysWooProductData = window.pysWooProductData || [];
5722                if(!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
5723                    return;
5724                var event = Utils.clone(options.dynamicEvents.woo_add_to_cart_on_button_click[this.tag()]);
5725
5726                if (product_type === Utils.PRODUCT_VARIABLE && !options.google_ads.wooVariableAsSimple) {
5727                    product_id = parseInt($form.find('input[name="variation_id"]').val());
5728                }
5729
5730                if (window.pysWooProductData.hasOwnProperty(product_id)) {
5731                    if (window.pysWooProductData[product_id].hasOwnProperty('google_ads')) {
5732
5733                        Utils.copyProperties(window.pysWooProductData[product_id]['google_ads']["params"], event.params);
5734                        event["ids"] = window.pysWooProductData[product_id]['google_ads']['ids']
5735                        event["conversion_labels"] = window.pysWooProductData[product_id]['google_ads']['conversion_labels']
5736
5737                        var groupValue = 0;
5738                        if(product_type === Utils.PRODUCT_GROUPED ) {
5739                            $form.find(".woocommerce-grouped-product-list .qty").each(function(index){
5740                                var childId = $(this).attr('name').replaceAll("quantity[","").replaceAll("]","");
5741                                var quantity = parseInt($(this).val());
5742                                if(isNaN(quantity)) {
5743                                    quantity = 0;
5744                                }
5745
5746                                var childItem = window.pysWooProductData[product_id]['google_ads'].grouped[childId];
5747
5748                                if(options.woo.addToCartOnButtonValueEnabled &&
5749                                    options.woo.addToCartOnButtonValueOption !== 'global') {
5750
5751                                    event.params.items.forEach(function(el,index,array) {
5752                                        if(el.id == childItem.content_id) {
5753                                            if(quantity > 0){
5754                                                el.quantity = quantity;
5755                                                el.price = childItem.price;
5756                                            } else {
5757                                                array.splice(index, 1);
5758                                            }
5759                                        }
5760                                    });
5761                                }
5762                                groupValue += childItem.price * quantity;
5763                            });
5764                            if(groupValue == 0) return;
5765                            event.params.value = groupValue;
5766                        } else {
5767                            // update items qty param
5768                            event.params.items[0].quantity = qty;
5769                        }
5770
5771
5772
5773                        // maybe customize value option
5774                        if (options.woo.addToCartOnButtonValueEnabled &&
5775                            options.woo.addToCartOnButtonValueOption !== 'global' &&
5776                            product_type !== Utils.PRODUCT_GROUPED) {
5777                            event.params.value =  event.params.value * qty;
5778                        }
5779
5780
5781
5782                        var eventName = is_external ? options.woo.affiliateEventName : event.name;
5783                        eventName = normalizeEventName(eventName);
5784
5785                        this.fireEvent(eventName, event);
5786
5787                    }
5788                }
5789
5790            },
5791
5792            onWooRemoveFromCartEvent: function (event) {
5793                this.fireEvent(event.name, event);
5794            },
5795
5796            onWooAffiliateEvent: function (product_id) {
5797                if(!options.dynamicEvents.woo_affiliate.hasOwnProperty(this.tag()))
5798                    return;
5799                var event = options.dynamicEvents.woo_affiliate[this.tag()];
5800
5801                if (window.pysWooProductData.hasOwnProperty(product_id)) {
5802                    if (window.pysWooProductData[product_id].hasOwnProperty('google_ads')) {
5803
5804                        event = Utils.clone(event)
5805                        Utils.copyProperties(window.pysWooProductData[product_id][this.tag()], event.params)
5806                        this.fireEvent(normalizeEventName(options.woo.affiliateEventName), event);
5807
5808                    }
5809                }
5810
5811            },
5812
5813            onWooPayPalEvent: function (event) {
5814                this.fireEvent(event.name, event);
5815            },
5816
5817            onEddAddToCartOnButtonEvent: function (download_id, price_index, qty) {
5818                if(!options.dynamicEvents.edd_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
5819                    return;
5820                var event = options.dynamicEvents.edd_add_to_cart_on_button_click[this.tag()];
5821
5822
5823                if (window.pysEddProductData.hasOwnProperty(download_id)) {
5824
5825                    var index;
5826
5827                    if (price_index) {
5828                        index = download_id + '_' + price_index;
5829                    } else {
5830                        index = download_id;
5831                    }
5832
5833                    if (window.pysEddProductData[download_id].hasOwnProperty(index)) {
5834                        if (window.pysEddProductData[download_id][index].hasOwnProperty('google_ads')) {
5835
5836                            event = Utils.clone(event)
5837                            Utils.copyProperties(window.pysEddProductData[download_id][index]['google_ads']['params'], event.params);
5838                            event.ids = window.pysEddProductData[download_id][index]['google_ads']['ids']
5839                            // update items qty param
5840                            //params.items[0].quantity = qty;
5841
5842                            this.fireEvent(event.name, event);
5843
5844                        }
5845                    }
5846
5847                }
5848
5849            },
5850
5851            onEddRemoveFromCartEvent: function (event) {
5852                this.fireEvent(event.name, event);
5853            },
5854            onPageScroll: function (event) {
5855                if (initialized && this.isEnabled()) {
5856                    this.fireEvent(event.name, event);
5857                }
5858            },
5859            onTime: function (event) {
5860                if (initialized && this.isEnabled()) {
5861                    this.fireEvent(event.name, event);
5862                }
5863            },
5864        };
5865
5866    }(options);
5867
5868    var GTM = function (options) {
5869
5870        var initialized = false;
5871
5872        var datalayer_name = 'dataLayer';
5873        /*
5874         * @param name
5875         * @param data
5876         */
5877        function fireEvent(name, event) {
5878            if(typeof window.pys_event_data_filter === "function" && window.pys_disable_event_filter(name,'gtm')) {
5879                return;
5880            }
5881
5882
5883            var eventParams = event.params;
5884            var data = event.params;
5885            var valuesArray = Object.values(event.trackingIds);
5886            var ids = valuesArray.filter(function (pixelId) {
5887                return !Utils.hideMatchingPixel(pixelId, 'gtm');
5888            })
5889            Utils.copyProperties(Utils.getRequestParams(), eventParams);
5890            var _fireEvent = function (tracking_id,name,params, event=null) {
5891
5892                var eventData = {};
5893                var ContainerCodeHasTag = !options.gtm.gtm_just_data_layer && tracking_id.length > 0;
5894                if(ContainerCodeHasTag) {
5895                    params['send_to'] = tracking_id;
5896                }
5897                else if(!options.gtm.gtm_just_data_layer){
5898                    return
5899                }
5900
5901                if (params.hasOwnProperty('ecommerce')) {
5902                    eventData.ecommerce = params.ecommerce;
5903                    delete params.ecommerce;
5904                }
5905
5906                var automatedParams = { ...params };
5907                [params['manualName'], 'manualName', 'triggerType'].forEach(key => delete automatedParams[key]);
5908                if(event && (!event.hasOwnProperty('hasAutoParam') || (event.hasOwnProperty('hasAutoParam') && event.hasAutoParam))) {
5909                    eventData.automatedParameters = automatedParams;
5910                }
5911
5912// Move custom parameters to eventData
5913
5914                if (params.hasOwnProperty(params['manualName'])) {
5915                    eventData[params['manualName']] = params[params['manualName']];
5916                    delete params[params['manualName']];
5917                }
5918
5919                ['manualName','triggerType'].forEach(key => {
5920                    if (params.hasOwnProperty(key)) {
5921                        eventData[key] = params[key];
5922                        delete params[key];
5923                    }
5924                });
5925
5926                eventData.manualDataLayer = options.gtm.gtm_dataLayer_name ?? 'dataLayer';
5927
5928                eventData.event = name;
5929
5930                if (options.debug) {
5931                    if (ContainerCodeHasTag){
5932                        console.log('[Google GTM #' + tracking_id + '] ' + name, eventData);
5933                    }
5934                    else {
5935                        console.log('[Google GTM push to "'+datalayer_name+'"] ' + name, eventData);
5936                    }
5937                }
5938                window[datalayer_name].push(eventData);
5939
5940                var customEvent = new CustomEvent('gtm_event_sent', {
5941                    detail: {
5942                        eventName: name,
5943                        params: eventData,
5944                        pixel_ids: tracking_id
5945                    }
5946                });
5947                window.dispatchEvent(customEvent);
5948
5949            };
5950
5951            var copyParams = Utils.copyProperties(eventParams, {}); // copy params because mapParamsToGTM can modify it
5952
5953            var params = mapParamsToGTM(ids,name,copyParams)
5954
5955            params.event_id = Utils.generateUniqueId(event);
5956
5957            _fireEvent(ids, name, params, event);
5958        }
5959
5960        function normalizeEventName(eventName) {
5961
5962            var matches = {
5963                ViewContent: 'view_item',
5964                AddToCart: 'add_to_cart',
5965                AddToWishList: 'add_to_wishlist',
5966                InitiateCheckout: 'begin_checkout',
5967                Purchase: 'purchase',
5968                Lead: 'generate_lead',
5969                CompleteRegistration: 'sign_up',
5970                AddPaymentInfo: 'set_checkout_option'
5971            };
5972
5973            return matches.hasOwnProperty(eventName) ? matches[eventName] : eventName;
5974
5975        }
5976
5977        function mapParamsToGTM(tag,name,param) {
5978            var hasGTM = false;
5979
5980            // end
5981            if (Array.isArray(tag)) {
5982                hasGTM = tag.some(function (element) {
5983                    return isGTM(element);
5984                });
5985            } else if(isGTM(tag)) {
5986                hasGTM = true;
5987            }
5988            if(hasGTM) {
5989                delete param.event_category;
5990                delete param.event_label;
5991
5992                delete param.analytics_storage;
5993                delete param.ad_storage;
5994                delete param.ad_user_data;
5995                delete param.ad_personalization;
5996
5997                if(name === 'search') {
5998                    param['search'] = param.search_term;
5999                    delete param.search_term;
6000                    delete param.dynx_itemid;
6001                    delete param.dynx_pagetype;
6002                    delete param.dynx_totalvalue;
6003                }
6004            }
6005            return param;
6006        }
6007
6008        function isGTM(tag) {
6009            return tag.indexOf('GTM') === 0;
6010        }
6011        /**
6012         * Public API
6013         */
6014        return {
6015            tag: function() {
6016                return "gtm";
6017            },
6018            isEnabled: function () {
6019                return options.hasOwnProperty('gtm');
6020            },
6021            getHidePixel: function(){
6022                if(this.isEnabled() && options.gtm.hasOwnProperty('hide_pixels'))
6023                {
6024                    return options.gtm.hide_pixels;
6025                }
6026                return [];
6027            },
6028            disable: function () {
6029                initialized = false;
6030            },
6031            updateEnhancedConversionData : function () {
6032                if (!initialized || !this.isEnabled()) {
6033                    return;
6034                }
6035                if(options.hasOwnProperty("tracking_analytics") && options.tracking_analytics.hasOwnProperty("userDataEnable") && options.tracking_analytics.userDataEnable) {
6036                    var advanced = Utils.getAdvancedMergeFormData(true);
6037                    if (Object.keys(advanced).length > 0) {
6038                        window[datalayer_name].push({'user_data' : advanced});
6039                    }
6040                }
6041            },
6042            loadPixel: function () {
6043
6044                if (initialized || !this.isEnabled() || !Utils.consentGiven('analytics')) {
6045                    return;
6046                }
6047                datalayer_name = options.gtm.gtm_dataLayer_name ?? 'dataLayer';
6048
6049                for (var i = 0; i < options.gtm.trackingIds.length; i++) {
6050                    var trackingId = options.gtm.trackingIds[i];
6051                    if (!Utils.hideMatchingPixel(trackingId, 'gtm') && !options.gtm.gtm_just_data_layer) {
6052                        console.log('[PYS] Google Tag Manager container code loaded');
6053                        Utils.loadGTMScript(trackingId);
6054                        break;
6055                    }
6056                }
6057
6058                if(options.gtm.gtm_just_data_layer) {
6059                    console.warn && console.warn("[PYS] Google Tag Manager container code placement set to OFF !!!");
6060                    console.warn && console.warn("[PYS] Data layer codes are active but GTM container must be loaded using custom coding !!!");
6061                    // Push consent defaults even when GTM script loading is handled externally.
6062                    // Fixes the case where gtm_just_data_layer=true with tracking IDs configured,
6063                    // which previously skipped loadGTMScript() entirely and never pushed defaults.
6064                    Utils.pushGTMConsentDefaults( datalayer_name );
6065                    if(options.gtm.trackingIds.length == 0){
6066                        Utils.loadGTMScript();
6067                    }
6068                }
6069
6070                if(options.hasOwnProperty("tracking_analytics") && options.tracking_analytics.hasOwnProperty("userDataEnable") && options.tracking_analytics.userDataEnable){
6071                    var advanced = Utils.getAdvancedMergeFormData(true);
6072                    if(Object.keys(advanced).length > 0){
6073                        window[datalayer_name].push({'user_data' : advanced});
6074                    }
6075                }
6076
6077
6078                var config = {};
6079
6080                if(options.user_id && options.user_id != 0) {
6081                    config.user_id = options.user_id;
6082                }
6083
6084                // Cross-Domain tracking
6085
6086                var ids = options.gtm.trackingIds.filter(function (pixelId) {
6087                    return !Utils.hideMatchingPixel(pixelId, 'gtm');
6088                });
6089
6090
6091                initialized = true;
6092
6093                Utils.fireStaticEvents('gtm');
6094            },
6095
6096            fireEvent: function (name, data) {
6097
6098                if (!initialized || !this.isEnabled()) {
6099                    return false;
6100                }
6101
6102                data.delay = data.delay || 0;
6103                data.params = data.params || {};
6104
6105                if (data.delay === 0) {
6106
6107                    fireEvent(name, data);
6108
6109                } else {
6110
6111                    setTimeout(function (name, params) {
6112                        fireEvent(name, params);
6113                    }, data.delay * 1000, name, data);
6114
6115                }
6116
6117                return true;
6118
6119            },
6120
6121            onAdSenseEvent: function (event) {
6122                this.fireEvent(event.name, event);
6123            },
6124
6125            onClickEvent: function (event) {
6126                this.fireEvent(event.name, event);
6127            },
6128
6129            onWatchVideo: function (event) {
6130                if(!event.hasOwnProperty("youtube_disabled")
6131                    || !event.youtube_disabled
6132                    || event.params.video_type !== "youtube") {
6133                    this.fireEvent(event.name, event);
6134                }
6135            },
6136
6137            onCommentEvent: function (event) {
6138
6139                this.fireEvent(event.name, event);
6140
6141            },
6142
6143            onFormEvent: function (event) {
6144
6145                this.fireEvent(event.name, event);
6146
6147            },
6148
6149            onDownloadEvent: function (event) {
6150
6151                this.fireEvent(event.name, event);
6152
6153            },
6154
6155            onWooAddToCartOnButtonEvent: function (product_id, prod_info = null) {
6156                if(!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
6157                    return;
6158                if (window.pysWooProductData.hasOwnProperty(product_id)) {
6159                    if (window.pysWooProductData[product_id].hasOwnProperty('gtm')) {
6160                        var event = Utils.clone(options.dynamicEvents.woo_add_to_cart_on_button_click[this.tag()]);
6161                        Utils.copyProperties(window.pysWooProductData[product_id]['gtm'].params, event.params)
6162                        event.trackingIds = window.pysWooProductData[product_id]['gtm']['trackingIds'];
6163
6164
6165                        if(prod_info)
6166                        {
6167                            item = event.params.hasOwnProperty('ecommerce') ? event.params.ecommerce.items[0] : event.params.items[0];
6168
6169                            if(prod_info['pys_list_name_productlist_id'])
6170                            {
6171                                item['item_list_id'] = prod_info['pys_list_name_productlist_id']
6172                            }
6173                            if(prod_info['pys_list_name_productlist_name'])
6174                            {
6175                                item['item_list_name'] =prod_info['pys_list_name_productlist_name']
6176                            }
6177                        }
6178                        this.fireEvent(event.name, event);
6179                    }
6180                }
6181
6182            },
6183
6184            onWooAddToCartOnSingleEvent: function (product_id, qty, product_type, is_external, $form, prod_info) {
6185                window.pysWooProductData = window.pysWooProductData || [];
6186
6187                if(!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
6188                    return;
6189                var event = Utils.clone(options.dynamicEvents.woo_add_to_cart_on_button_click[this.tag()]);
6190
6191                if (product_type === Utils.PRODUCT_VARIABLE && !options.gtm.wooVariableAsSimple) {
6192                    product_id = parseInt($form.find('input[name="variation_id"]').val());
6193                }
6194
6195                if (window.pysWooProductData.hasOwnProperty(product_id)) {
6196                    if (window.pysWooProductData[product_id].hasOwnProperty('gtm')) {
6197
6198                        Utils.copyProperties(window.pysWooProductData[product_id]['gtm'].params, event.params);
6199
6200                        params = event.params.hasOwnProperty('ecommerce') ? event.params.ecommerce : event.params;
6201
6202                        if(product_type === Utils.PRODUCT_GROUPED ) {
6203                            var groupValue = 0;
6204                            $form.find(".woocommerce-grouped-product-list .qty").each(function(index){
6205                                var childId = $(this).attr('name').replaceAll("quantity[","").replaceAll("]","");
6206                                var quantity = parseInt($(this).val());
6207                                if(isNaN(quantity)) {
6208                                    quantity = 0;
6209                                }
6210                                var childItem = window.pysWooProductData[product_id]['gtm'].grouped[childId];
6211
6212                                params.items.forEach(function(el,index,array) {
6213                                    if(el.id == childItem.content_id) {
6214                                        if(quantity > 0){
6215                                            el.quantity = quantity;
6216                                            el.price = childItem.price;
6217                                        } else {
6218                                            array.splice(index, 1);
6219                                        }
6220                                    }
6221                                });
6222                                groupValue += childItem.price * quantity;
6223                            });
6224
6225
6226
6227                            if(options.woo.addToCartOnButtonValueEnabled &&
6228                                options.woo.addToCartOnButtonValueOption !== 'global' &&
6229                                params.hasOwnProperty('value')) {
6230                                params.value = groupValue;
6231                            }
6232
6233                            if(groupValue == 0) return; // skip if no items selected
6234                        } else {
6235                            // update items qty param
6236                            params.items[0].quantity = qty;
6237                        }
6238
6239                        // maybe customize value option
6240                        if (options.woo.addToCartOnButtonValueEnabled &&
6241                            options.woo.addToCartOnButtonValueOption !== 'global' &&
6242                            product_type !== Utils.PRODUCT_GROUPED)
6243                        {
6244                            if(params.hasOwnProperty('value')) {
6245                                params.value = params.items[0].price * qty;
6246                            }
6247                        }
6248
6249                        if(prod_info)
6250                        {
6251                            if(prod_info['pys_list_name_productlist_id'])
6252                            {
6253                                params.items[0]['item_list_id'] = prod_info['pys_list_name_productlist_id']
6254                            }
6255                            if(prod_info['pys_list_name_productlist_name'])
6256                            {
6257                                params.items[0]['item_list_name'] =prod_info['pys_list_name_productlist_name']
6258                            }
6259                        }
6260
6261                        var eventName = is_external ? options.woo.affiliateEventName : event.name;
6262                        eventName = normalizeEventName(eventName);
6263
6264                        this.fireEvent(eventName, event);
6265
6266                    }
6267                }
6268
6269            },
6270
6271            onWooCheckoutProgressStep: function (event) {
6272                this.fireEvent(event.name, event);
6273            },
6274
6275            onWooSelectContent: function (event) {
6276                const select_prod_list = {};
6277
6278                if (event.params.items[0].item_list_name !== undefined) {
6279                    select_prod_list.list_name = event.params.items[0].item_list_name;
6280                }
6281
6282                if (event.params.items[0].item_list_id !== undefined) {
6283                    select_prod_list.list_id = event.params.items[0].item_list_id;
6284                }
6285                const url = new URL(window.location.href);
6286                select_prod_list.url = url.origin + url.pathname;
6287                Cookies.set('select_prod_list', JSON.stringify(select_prod_list), { expires: 1,path: '/' });
6288                this.fireEvent(event.name, event);
6289            },
6290
6291            onWooRemoveFromCartEvent: function (event) {
6292                this.fireEvent(event.name, event);
6293            },
6294
6295            onWooAffiliateEvent: function (product_id) {
6296                if(!options.dynamicEvents.woo_affiliate.hasOwnProperty(this.tag()))
6297                    return;
6298                var event = options.dynamicEvents.woo_affiliate[this.tag()];
6299
6300                if (window.pysWooProductData.hasOwnProperty(product_id)) {
6301                    if (window.pysWooProductData[product_id].hasOwnProperty('gtm')) {
6302
6303                        event = Utils.clone(event );
6304                        Utils.copyProperties(window.pysWooProductData[product_id][this.tag()], event.params)
6305                        this.fireEvent(normalizeEventName(options.woo.affiliateEventName), event);
6306
6307                    }
6308                }
6309
6310            },
6311
6312            onWooPayPalEvent: function (event) {
6313                this.fireEvent(event.name, event);
6314            },
6315
6316            onEddAddToCartOnButtonEvent: function (download_id, price_index, qty) {
6317                if(!options.dynamicEvents.edd_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
6318                    return;
6319                var event = Utils.clone(options.dynamicEvents.edd_add_to_cart_on_button_click[this.tag()]);
6320
6321
6322                if (window.pysEddProductData.hasOwnProperty(download_id)) {
6323
6324                    var index;
6325
6326                    if (price_index) {
6327                        index = download_id + '_' + price_index;
6328                    } else {
6329                        index = download_id;
6330                    }
6331
6332                    if (window.pysEddProductData[download_id].hasOwnProperty(index)) {
6333                        if (window.pysEddProductData[download_id][index].hasOwnProperty('gtm')) {
6334
6335                            Utils.copyProperties(window.pysEddProductData[download_id][index]['gtm'].params, event.params);
6336                            item = event.params.hasOwnProperty('ecommerce') ? event.params.ecommerce.items[0] : event.params.items[0];
6337                            // update items qty param
6338                            item.quantity = qty;
6339
6340                            this.fireEvent(event.name,event);
6341
6342                        }
6343                    }
6344
6345                }
6346
6347            },
6348
6349            onEddRemoveFromCartEvent: function (event) {
6350                this.fireEvent(event.name, event);
6351            },
6352
6353            onPageScroll: function (event) {
6354                if (initialized && this.isEnabled()) {
6355                    this.fireEvent(event.name, event);
6356                }
6357            },
6358            onTime: function (event) {
6359                if (initialized && this.isEnabled()) {
6360                    this.fireEvent(event.name, event);
6361                }
6362            },
6363        };
6364
6365    }(options);
6366
6367    var getPixelBySlag = function getPixelBySlag(slug) {
6368        switch (slug) {
6369            case "facebook": return window.pys.Facebook;
6370            case "ga": return window.pys.Analytics;
6371            case "gtm": return window.pys.GTM;
6372            case "google_ads": return window.pys.GAds;
6373            case "bing": return window.pys.Bing;
6374            case "pinterest": return window.pys.Pinterest;
6375            case "tiktok": return window.pys.TikTok;
6376            case "reddit": return window.pys.Reddit;
6377        }
6378    }
6379
6380    window.pys = window.pys || {};
6381    window.pys.Facebook = Facebook;
6382    window.pys.Analytics = Analytics;
6383    window.pys.GAds = GAds;
6384    window.pys.GTM = GTM;
6385    window.pys.Utils = Utils;
6386    window.pys.TikTok = TikTok;
6387    window.pys.getPixelBySlag = getPixelBySlag;
6388
6389    // Allow external scripts (e.g. generatePixelCode fragments) to refresh
6390    // the uniqueId cache for a given event key, so that each new add_to_cart
6391    // action gets a fresh shared ID across all pixels.
6392    window.pys.setEventUniqueId = function(idKey, newId) {
6393        uniqueId[idKey] = newId;
6394    };
6395
6396    // Export getPixelBySlag globally for backward compatibility
6397    window.getPixelBySlag = getPixelBySlag;
6398
6399    function pysNormalInit() {
6400
6401        if(Cookies.get('form_track'))
6402        {
6403            Cookies.remove('form_track')
6404        }
6405
6406        if($("#pys_late_event").length > 0) {
6407            var dirAttr = $("#pys_late_event").attr("dir");
6408            if (dirAttr) {
6409                try {
6410                    var events = JSON.parse(dirAttr);
6411                } catch (e) {
6412                    console.warn("Invalid JSON in pys_late_event dir attribute:", e);
6413                }
6414            } else {
6415                console.warn("pys_late_event dir attribute is undefined or empty");
6416            }
6417            if (events) {
6418                for (var platform in events) {
6419                    if (events.hasOwnProperty(platform)) {
6420                        var platformEvents = events[platform];
6421                        platformEvents.forEach(function (event) {
6422                            var eventData = {};
6423                            eventData[event.e_id] = [event];
6424                            if (options.staticEvents.hasOwnProperty(platform)) {
6425                                Object.assign(options.staticEvents[platform], eventData);
6426                            } else {
6427                                options.staticEvents[platform] = eventData;
6428                            }
6429                        });
6430                    }
6431                }
6432            }
6433        }
6434
6435        var Pinterest = Utils.setupPinterestObject();
6436        var Bing = Utils.setupBingObject();
6437	    var Reddit = Utils.setupRedditObject();
6438        if(options.hasOwnProperty('cookie'))
6439        {
6440            if(options.cookie.externalID_disabled_by_api || options.cookie.disabled_all_cookie)
6441            {
6442                Cookies.remove('pbid')
6443            }
6444            if(options.cookie.disabled_advanced_form_data_cookie || options.cookie.disabled_all_cookie)
6445            {
6446                Cookies.remove('pys_advanced_form_data')
6447            }
6448
6449            if(options.cookie.disabled_landing_page_cookie || !options.enable_lading_page_param || options.cookie.disabled_all_cookie)
6450            {
6451                Cookies.remove('pys_landing_page', { path: '/',domain: domain })
6452                Cookies.remove('last_pys_landing_page', { path: '/',domain: domain })
6453            }
6454            if(options.cookie.disabled_trafficsource_cookie || options.cookie.disabled_all_cookie)
6455            {
6456                Cookies.remove('pysTrafficSource', { path: '/',domain: domain })
6457                Cookies.remove('last_pysTrafficSource', { path: '/',domain: domain })
6458            }
6459            if(options.cookie.disabled_first_visit_cookie || options.cookie.disabled_all_cookie)
6460            {
6461                Cookies.remove('pys_first_visit', { path: '/',domain: domain })
6462
6463            }
6464            if(options.cookie.disabled_utmTerms_cookie || options.cookie.disabled_all_cookie)
6465            {
6466                $.each(Utils.utmTerms, function (index, name) {
6467                    Cookies.remove('pys_' + name, { path: '/',domain: domain })
6468                });
6469                $.each(Utils.utmTerms, function (index, name) {
6470                    Cookies.remove('last_pys_' + name, { path: '/',domain: domain })
6471                });
6472            }
6473            if(options.cookie.disabled_utmId_cookie || options.cookie.disabled_all_cookie)
6474            {
6475                $.each(Utils.utmId,function(index,name) {
6476                    Cookies.remove('pys_' + name, { path: '/',domain: domain })
6477                })
6478                $.each(Utils.utmId,function(index,name) {
6479                    Cookies.remove('last_pys_' + name, { path: '/',domain: domain })
6480                });
6481            }
6482        }
6483
6484        if (options.gdpr.cookie_law_info_integration_enabled) {
6485            var cli_cookie = Cookies.get('cookieyes-consent') ?? Cookies.get('wt_consent') ?? Cookies.get('viewed_cookie_policy');
6486
6487            if (typeof cli_cookie !== 'undefined') {
6488                if (cli_cookie === Cookies.get('cookieyes-consent') || cli_cookie === Cookies.get('wt_consent')) {
6489                    if (getCookieYes('analytics') === 'yes') {
6490                        Utils.manageCookies();
6491                    }
6492                } else if (cli_cookie === Cookies.get('viewed_cookie_policy') && cli_cookie == 'yes') {
6493                    Utils.manageCookies();
6494                }
6495            }
6496        }
6497
6498        if ( options.gdpr.consent_magic_integration_enabled && typeof CS_Data !== "undefined" ) {
6499            if ( CS_Data.cs_script_cat.pys == CS_Data.cs_necessary_cat_id || CS_Data.cs_script_cat.pys == 0 ) {
6500                Utils.manageCookies();
6501            } else if ( Cookies.get( 'cs_enabled_cookie_term' + CS_Data.test_prefix + '_' + CS_Data.cs_script_cat.pys ) == 'yes' ) {
6502                Utils.manageCookies();
6503            }
6504        } else {
6505            Utils.manageCookies();
6506        }
6507
6508        Utils.initializeRequestParams();
6509        Utils.setupGdprCallbacks();
6510
6511        if ( options.enable_auto_save_advance_matching ) {
6512            let override = options.data_persistency == 'recent_data';
6513            // Setup Advanced Form Data
6514            if ( options.advance_matching_form.enable_advance_matching_forms ) {
6515
6516                // Handle Email fields
6517                $( document ).on( "blur", "input[type='email']", function () {
6518                    // SECURITY: Ignore fields located inside the Authorize.Net payment block
6519                    if ( $( this ).closest('.payment_method_anet').length > 0 ) return;
6520
6521                    let email = $( this ).val().trim().toLowerCase();
6522                    if ( Utils.validateEmail( email ) ) {
6523                        Utils.saveAdvancedFormData( email, null, null, null, override );
6524                    }
6525                } )
6526
6527                // Handle Telephone fields (This is where Credit Card numbers were being captured)
6528                $( document ).on( "blur", "input[type='tel']", function () {
6529                    // SECURITY: Ignore fields located inside the Authorize.Net payment block
6530                    if ( $( this ).closest('.payment_method_anet').length > 0 ) return;
6531
6532                    let phone = $( this ).val().trim().replace( /\D/g, "" );
6533                    if ( phone.length > 5 ) {
6534                        Utils.saveAdvancedFormData( null, phone, null, null, override );
6535                    }
6536                } )
6537
6538                // Handle Text fields
6539                $( document ).on( "blur", "input[type='text']", function () {
6540                    // SECURITY: Ignore fields located inside the Authorize.Net payment block
6541                    if ( $( this ).closest('.payment_method_anet').length > 0 ) return;
6542
6543                    let name;
6544                    if ( $( this ).attr( "name" ) && $( this ).attr( "name" ) != '' ) {
6545                        name = $( this ).attr( "name" ).trim()
6546                    }
6547                    if ( name && options.advance_matching_form.advance_matching_fn_names.includes( name ) ) {
6548                        let value = $( this ).val().trim();
6549                        if ( value.length > 0 ) {
6550                            Utils.saveAdvancedFormData( null, null, value, null, override );
6551                        }
6552                    }
6553                    if ( name && options.advance_matching_form.advance_matching_ln_names.includes( name ) ) {
6554                        let value = $( this ).val().trim();
6555                        if ( value.length > 0 ) {
6556                            Utils.saveAdvancedFormData( null, null, null, value, override );
6557                        }
6558                    }
6559                    if ( name && options.advance_matching_form.advance_matching_tel_names.includes( name ) ) {
6560                        let value = $( this ).val().trim();
6561                        if ( value.length > 0 ) {
6562                            Utils.saveAdvancedFormData( null, value, null, null, override );
6563                        }
6564                    }
6565                    if ( name && options.advance_matching_form.advance_matching_em_names.includes( name ) ) {
6566                        let email = $( this ).val().trim().toLowerCase();
6567
6568                        if ( Utils.validateEmail( email ) ) {
6569                            Utils.saveAdvancedFormData( email, null, null, null, false );
6570                        }
6571                    }
6572                } )
6573            }
6574
6575            //Setup Advanced Url Data
6576            if ( Object.keys( options.advance_matching_url ).length > 0 && options.advance_matching_url.enable_advance_matching_url ) {
6577                const url_params = new URLSearchParams( window.location.search );
6578                url_params.forEach( ( value, key ) => {
6579                    if ( options.advance_matching_url.advance_matching_fn_names.includes( key ) ) {
6580                        Utils.saveAdvancedFormData( null, null, value.trim(), null, override );
6581                    }
6582
6583                    if ( options.advance_matching_url.advance_matching_ln_names.includes( key ) ) {
6584                        Utils.saveAdvancedFormData( null, null, null, value.trim(), override );
6585                    }
6586
6587                    if ( options.advance_matching_url.advance_matching_tel_names.includes( key ) ) {
6588                        Utils.saveAdvancedFormData( null, value.trim(), null, null, override );
6589                    }
6590
6591                    if ( options.advance_matching_url.advance_matching_em_names.includes( key ) ) {
6592                        let email = value.trim().toLowerCase()
6593                        if ( Utils.validateEmail( email ) ) {
6594                            Utils.saveAdvancedFormData( email, null, null, null, override );
6595                        }
6596                    }
6597                } );
6598            }
6599        }
6600
6601        // setup Click Event
6602        if (
6603            options.dynamicEvents.hasOwnProperty("automatic_event_internal_link") ||
6604            options.dynamicEvents.hasOwnProperty("automatic_event_outbound_link") ||
6605            options.dynamicEvents.hasOwnProperty("automatic_event_tel_link") ||
6606            options.dynamicEvents.hasOwnProperty("automatic_event_email_link") ||
6607            options.dynamicEvents.hasOwnProperty("automatic_event_download")
6608        ) {
6609
6610            $(document).onFirst('click', 'a, button, input[type="button"], input[type="submit"]', function (e) {
6611
6612                var $elem = $(this);
6613
6614
6615                // Download
6616                if(options.dynamicEvents.hasOwnProperty("automatic_event_download")) {
6617                    var isFired = false;
6618                    if ($elem.is('a')) {
6619                        var href = $elem.attr('href');
6620                        if (typeof href !== "string") {
6621                            return;
6622                        }
6623                        href = href.trim();
6624                        var extension = Utils.getLinkExtension(href);
6625                        var track_download = false;
6626
6627                        if (extension.length > 0) {
6628
6629                            if(options.dynamicEvents.hasOwnProperty("automatic_event_download") ) {
6630                                var pixels = Object.keys(options.dynamicEvents.automatic_event_download);
6631                                for (var i = 0; i < pixels.length; i++) {
6632                                    var event = Utils.clone(options.dynamicEvents.automatic_event_download[pixels[i]]);
6633                                    var extensions = event.extensions;
6634                                    if (extensions.includes(extension)) {
6635
6636                                        if(pixels[i] == "tiktok" || pixels[i] == "reddit") {
6637                                            getPixelBySlag(pixels[i]).fireEvent(event.name, event);
6638                                        } else {
6639                                            if (options.enable_remove_download_url_param) {
6640                                                href = href.split('?')[0];
6641                                            }
6642                                            event.params.download_url = href;
6643                                            event.params.download_type = extension;
6644                                            event.params.download_name = Utils.getLinkFilename(href);
6645                                            getPixelBySlag(pixels[i]).onDownloadEvent(event);
6646                                        }
6647
6648                                        isFired = true;
6649                                    }
6650                                }
6651                            }
6652                        }
6653                    }
6654                    if(isFired) { // prevent duplicate events on the same element
6655                        return;
6656                    }
6657                }
6658
6659
6660                if (!e.hasOwnProperty('originalEvent')) {
6661                    return;
6662                }
6663                if($elem.hasClass("add_to_cart_button") ||
6664                    $elem.hasClass("single_add_to_cart_button") ) { // add_to_cart_button fire in woo
6665                    return;
6666                }
6667
6668                if(options.dynamicEvents.hasOwnProperty("wcf_add_to_cart_on_next_step_click")
6669                    && $elem.hasClass("wcf-next-step-link")) {
6670                    return;// add_to_cart_button fire in woo cf
6671                }
6672                if(options.dynamicEvents.hasOwnProperty("wcf_add_to_cart_on_bump_click")
6673                    && $elem.hasClass("wcf-bump-order-cb")) {
6674                    return;// add_to_cart_button fire in woo cf
6675                }
6676
6677                if($elem.hasClass("remove_from_cart_button") ) { // cancel remove from cart
6678                    return;
6679                }
6680                if($elem.hasClass("remove") ) { // cancel remove from cart
6681                    if($elem.parents('.cart_item').length || $elem.parents('.mini_cart_item').length)
6682                        return;
6683                }
6684                if($elem.attr("name") == "update_cart" || $elem.attr("name") == "apply_coupon") { // cancel update  c
6684art or coupon button
6685                    return;
6686                }
6687
6688
6689                if ($elem.hasClass('pys_block')) {
6690                    return; // avoiding fake double clicks from Affiliate event
6691                }
6692                var text = "";
6693                var target_url = "";
6694                var linkType = "Internal Click";
6695
6696                if ($elem.is('a')) {
6697                    var href = $elem.attr('href');
6698
6699                    // fixes #112
6700                    if (typeof href !== "string") {
6701                        return;
6702                    }
6703                    href = href.trim();
6704
6705                    text = $elem.contents().filter(function() {
6706                        return this.nodeType === 3; // Filter text nodes only
6707                    }).text().trim();
6708                    if(options.enable_remove_target_url_param) {
6709                        target_url = href.split('?')[0];
6710                    } else {
6711                        target_url = href
6712                    }
6713
6714
6715                    //Email Event
6716                    if ( href.startsWith( 'mailto:' ) ) {
6717                        if ( options.triggerEventTypes.hasOwnProperty( "email_link" ) ) {
6718                            return;
6719                        } else {
6720                            setupEmailLinks();
6721                        }
6722
6723                        return; // not fire next
6724                    }
6725
6726                    // Phone
6727                    if (href.startsWith('tel:')) {
6728                        if(options.dynamicEvents.hasOwnProperty("automatic_event_tel_link")) {
6729                            var pixels = Object.keys(options.dynamicEvents.automatic_event_tel_link);
6730                            for(var i = 0;i<pixels.length;i++) {
6731                                var event = Utils.clone(options.dynamicEvents.automatic_event_tel_link[pixels[i]]);
6732                                if ( pixels[i] !== 'tiktok' && pixels[i] !== 'reddit') {
6733                                    Utils.copyProperties(Utils.getRequestParam
6733s(), event.params);
6734                                }
6735                                getPixelBySlag(pixels[i]).fireEvent(event.name, event);
6736                            }
6737                        }
6738                        return; // not fire next
6739                    }
6740
6741                    if (href.startsWith('http')) {
6742                        // link type
6743                        var host = $elem.context != undefined ? $elem.context.host : $elem[0].host;
6744                        if (document.location.host != host) {
6745                            linkType = 'External Click';
6746                        }
6747                    }
6748                } else if ($elem.is('button')) {
6749                    if( $elem.hasClass("forminator-button-submit")) {
6750                        //disable duplicate events
6751                        return;
6752                    }
6753                    text = $elem.contents().filter(function() {
6754                        return this.nodeType === 3; // Filter text nodes only
6755                    }).text().trim();
6756                } else if ($elem.is('input[type="button"]')) {
6757                    text = $elem.val();
6758                } else if ($elem.is('input[type="submit"]')) {
6759                    if ( $elem.parents("form.comment-form")) {
6760                        //disable duplicate events
6761                        return;
6762                    }
6763                    if ($elem.parents("form")) {
6764                        //disable duplicate events
6765                        return;
6766                    }
6767                    text = $elem.val();
6768                } else {
6769                    return;
6770                }
6771
6772
6773
6774                text = Utils.filterEmails(text);
6775
6776
6777                if( linkType === "Internal Click"
6778                    && options.dynamicEvents.hasOwnProperty("automatic_event_internal_link")
6779                ) {
6780                    var pixels = Object.keys(options.dynamicEvents.automatic_event_internal_link);
6781
6782                    for(var i = 0;i<pixels.length;i++) {
6783                        var event = Utils.clone(options.dynamicEvents.automatic_event_internal_link[pixels[i]]);
6784
6785	                    if(pixels[i] !== "tiktok" && pixels[i] !== "reddit") { // TT and reddit don't support custom parameters
6786                            event.params["text"] = text;
6787                            if(target_url){
6788                                event.params["target_url"] = target_url;
6789                            }
6790                            Utils.copyProperties(Utils.getRequestParam
6790s(), event.params);
6791                        }
6792
6793
6794                        getPixelBySlag(pixels[i]).fireEvent(event.name, event);
6795                    }
6796                }
6797
6798                if( linkType === "External Click"
6799                    && options.dynamicEvents.hasOwnProperty("automatic_event_outbound_link")
6800                ) {
6801                    var pixels = Object.keys(options.dynamicEvents.automatic_event_outbound_link);
6802
6803                    for(var i = 0;i<pixels.length;i++) {
6804                        var event = Utils.clone(options.dynamicEvents.automatic_event_outbound_link[pixels[i]]);
6805
6806                        if(pixels[i] !== "tiktok" && pixels[i] !== "reddit") { // TT and reddit don't support custom parameters
6807                            event.params["text"] = text;
6808                            if(target_url){
6809                                event.params["target_url"] = target_url;
6810                            }
6811                            Utils.copyProperties(Utils.getRequestParams(), event.params);
6812                        }
6813
6814
6815                        getPixelBySlag(pixels[i]).fireEvent(event.name, event);
6816                    }
6817                }
6818
6819
6820
6821
6822            });
6823
6824        }
6825
6826        // setup AdSense Event
6827        if (options.dynamicEvents.hasOwnProperty("automatic_event_adsense")) {
6828
6829            var isOverGoogleAd = false;
6830
6831            $(document)
6832                .on('mouseover', 'ins iframe', function () { //class adsbygoogle adsbygoogle-noablate ??
6833                    isOverGoogleAd = true;
6834                })
6835                .on('mouseout', 'iframe', function () {
6836                    isOverGoogleAd = false;
6837                });
6838
6839            $(window)
6840                .on( "blur",function () {
6841                    if (isOverGoogleAd) {
6842                        if(options.dynamicEvents.hasOwnProperty("automatic_event_adsense")) {
6843                            var pixels = Object.keys(options.dynamicEvents.automatic_event_adsense);
6844                            for (var i = 0; i < pixels.length; i++) {
6845                                var event = Utils.clone(options.dynamicEvents.automatic_event_adsense[pixels[i]]);
6846                                if ( pixels[i] !== 'tiktok' && pixels[i] !== 'reddit') {
6847                                    Utils.copyProperties(Utils.getRequestParam
6847s(), event.params);
6848                                }
6849                                getPixelBySlag(pixels[i]).onAdSenseEvent(event);
6850                            }
6851                        }
6852
6853                        $.each(options.triggerEventTypes, function (triggerType, events) {
6854                            $.each(events, function (eventId, triggers) {
6855                                switch (triggerType) {
6856                                    case 'ad_sense_click':
6857                                        Utils.handleTriggerFired(eventId, triggerType);
6858                                        break;
6859                                }
6860                            });
6861                        });
6862                    }
6863                })
6864                .trigger("focus");
6865
6866        }
6867
6868        //setup adsense for custom events
6869        var dynamicAdsenseEventsTriggers = 0
6870        $.each(options.triggerEventTypes, function (triggerType, events) {
6871            if(triggerType == "ad_sense_click") {
6872                dynamicAdsenseEventsTriggers++;
6873            }
6874        });
6875        if (dynamicAdsenseEventsTriggers > 0) {
6876
6877            var isOverGoogleAd = false;
6878
6879            $(document)
6880                .on('mouseover', 'ins > ins > iframe', function () {
6881                    isOverGoogleAd = true;
6882                })
6883                .on('mouseout', 'iframe', function () {
6884                    isOverGoogleAd = false;
6885                });
6886
6887            $(window)
6888                .on( "blur",function () {
6889                    if (isOverGoogleAd) {
6890
6891                        $.each(options.triggerEventTypes, function (triggerType, events) {
6892                            $.each(events, function (eventId, triggers) {
6893                                switch (triggerType) {
6894                                    case 'ad_sense_click':
6895                                        Utils.handleTriggerFired(eventId, triggerType);
6896                                        break;
6897                                }
6898                            });
6899                        });
6900                    }
6901                })
6902                .trigger("focus");
6903
6904        }
6905
6906
6907        // page scroll event
6908        if (options.dynamicEvents.hasOwnProperty("automatic_event_scroll")
6909        ) {
6910
6911            var singlePageScroll = function () {
6912
6913
6914                var docHeight = $(document).height() - $(window).height();
6915                var isFired = false;
6916
6917                if (options.dynamicEvents.hasOwnProperty("automatic_event_scroll")) {
6918                    var pixels = Object.keys(options.dynamicEvents.automatic_event_scroll);
6919                    for(var i = 0;i<pixels.length;i++) {
6920                        var event = Utils.clone(options.dynamicEvents.automatic_event_scroll[pixels[i]]);
6921                        var scroll = Math.round(docHeight * event.scroll_percent / 100)// convert % to absolute positions
6922
6923                        if(scroll < $(window).scrollTop()) {
6924                            if ( pixels[i] !== 'tiktok' && pixels[i] !== 'reddit') {
6925                                Utils.copyProperties(Utils.getRequestParam
6925s(), event.params);
6926                            }
6927                            getPixelBySlag(pixels[i]).onPageScroll(event);
6928                            isFired = true
6929                        }
6930                    }
6931                }
6932                if(isFired) {
6933                    $(document).off("scroll",singlePageScroll);
6934                }
6935            }
6936            $(document).on("scroll",singlePageScroll);
6937        }
6938
6939
6940        if (options.dynamicEvents.hasOwnProperty("automatic_event_time_on_page")) {
6941            var pixels = Object.keys(options.dynamicEvents.automatic_event_time_on_page);
6942            var time = options.dynamicEvents.automatic_event_time_on_page[pixels[0]].time_on_page; // the same for all pixel
6943            setTimeout(function(){
6944                for(var i = 0;i<pixels.length;i++) {
6945                    var event = Utils.clone(options.dynamicEvents.automatic_event_time_on_page[pixels[i]]);
6946                    if ( pixels[i] !== 'tiktok' && pixels[i] !== 'reddit') {
6947                        Utils.copyProperties(Utils.getRequestParam
6947s(), event.params);
6948                    }
6949                    getPixelBySlag(pixels[i]).onTime(event);
6950                }
6951            },time*1000);
6952        }
6953
6954        // setup Dynamic events
6955
6956        $.each(options.triggerEventTypes, function (triggerType, events) {
6957
6958            $.each(events, function (eventId, triggers) {
6959                switch (triggerType) {
6960                    case 'url_click':
6961                        //@see: Utils.setupURLClickEvents()
6962                        break;
6963
6964                    case 'css_click':
6965                        var cssTriggerData  = Array.isArray(triggers) ? { selectors: triggers, click_count: 1, click_time_limit: 0 } : triggers;
6966                        var cssSelectors    = cssTriggerData.selectors || triggers;
6967                        var cssClickCount   = cssTriggerData.click_count || 1;
6968                        var cssTimeLimit    = parseInt(cssTriggerData.click_time_limit, 10) || 0;
6969                        Utils.setupCSSClickEvents(eventId, cssSelectors, triggerType, cssClickCount, cssTimeLimit);
6970                        break;
6971
6972                    case 'css_mouseover':
6973                        Utils.setupMouseOverClickEvents(eventId, triggers, triggerType);
6974                        break;
6975
6976                    case 'scroll_pos':
6977                        Utils.setupScrollPosEvents(eventId, triggers, triggerType);
6978                        break;
6979                    case 'comment':
6980                        Utils.setupCommentEvents(eventId, triggers);
6981                        break;
6982                    case 'video_view':
6983                        //@see: Utils.checkYouTubeCompletion() and Utils.addYouTubeEvents()
6984                        break;
6985
6986                    case 'form_field':
6987                        Utils.setupFormFieldEvents(eventId, triggers, triggerType);
6988                        break;
6989
6990                    case 'copy_element':
6991                        Utils.setupCopyElementEvents(eventId, triggers);
6992                        break;
6993
6994                    case 'video_speed':
6995                        Utils.setupVideoSpeedEvents(eventId, triggers);
6996                        break;
6997                }
6998
6999            });
7000
7001            if ( triggerType == "email_link" ) {
7002                Utils.setupEmailLinkEvents( events )
7003            }
7004
7005        });
7006
7007        // Global RageClick tracking
7008        if (options.dynamicEvents.hasOwnProperty('automatic_event_rage_click')) {
7009            (function() {
7010                var RAGE_THRESHOLD = Math.max(2, parseInt(options.rage_click_threshold, 10) || 3);
7011                // rage_click_time_limit from admin in seconds; allow floats (e.g. 1.5); minimum 0.5s.
7012                var RAGE_TIMEOUT   = Math.max(0.5, parseFloat(options.rage_click_time_limit) || 2) * 1000;
7013                var rageMap        = typeof WeakMap !== 'undefined' ? new WeakMap() : null;
7014
7015                if (!rageMap) return;
7016
7017                // Expanded interactive selector — includes developer-marked elements.
7018                var INTERACTIVE_SELECTOR =
7019                    'button, a, input, select, textarea, label, ' +
7020                    '[role="button"], [role="link"], [onclick], [tabindex], [data-track], [data-testid]';
7021
7022                // Walk up to the nearest meaningful interactive ancestor.
7023                // Returns null when none found — non-interactive clicks are silently ignored.
7024                // Note: having an id alone does NOT make an element interactive
7025                // (e.g. div#comments, div#reviews are structural, not clickable).
7026                function findClickTarget(el) {
7027                    while (el && el !== document.body) {
7028                        if (el.matches && el.matches(INTERACTIVE_SELECTOR)) {
7029                            return el;
7030                        }
7031                        el = el.parentElement;
7032                    }
7033                    return null;
7034                }
7035
7036                // Build a breadcrumb path: up to 3 DOM nodes ending at el.
7037                // Example: "nav#menu > ul.links > button.cta"
7038                function buildElementPath(el, depth) {
7039                    depth = depth || 3;
7040                    var parts = [];
7041                    var cur = el;
7042                    while (cur && cur !== document.body && parts.length < depth) {
7043                        var tag = cur.tagName ? cur.tagName.toLowerCase() : '';
7044                        var id  = cur.id ? '#' + cur.id : '';
7045                        var rawCls = cur.className && typeof cur.className === 'string'
7046                            ? cur.className
7047                            : (cur.className && cur.className.baseVal ? cur.className.baseVal : '');
7048                        var cls = rawCls ? '.' + rawCls.trim().split(/\s+/).slice(0, 2).join('.') : '';
7049                        parts.unshift(tag + id + cls);
7050                        cur = cur.parentElement;
7051                    }
7052                    return parts.join(' > ');
7053                }
7054
7055                function describeElement(el) {
7056                    var raw = el.className && (typeof el.className === 'string'
7057                        ? el.className
7058                        : (el.className.baseVal || ''));
7059                    var classes = raw ? raw.trim().split(/\s+/).slice(0, 3).join(' ') : '';
7060
7061                    var text = (el.innerText || el.value || el.getAttribute('aria-label') || '')
7062                        .trim().replace(/\s+/g, ' ').slice(0, 80);
7063
7064                    var href = el.tagName === 'A' ? (el.getAttribute('href') || '') : '';
7065                    var tag  = el.tagName ? el.tagName.toLowerCase() : '';
7066                    var path = buildElementPath(el);
7067
7068                    // Only include fields with non-empty values — don't pollute the event
7069                    // payload with empty strings that add noise to dashboards.
7070                    var result = {};
7071                    if (tag)     { result.element_tag = tag; result.element = tag; } // element = backward-compat alias
7072                    if (el.id)   result.element_id      = el.id;
7073                    if (classes) result.element_classes  = classes;
7074                    if (text)    result.element_text     = text;
7075                    if (href)    result.element_href     = href;
7076                    if (path)    result.element_path     = path;
7077                    return result;
7078                }
7079
7080                document.addEventListener('click', function(event) {
7081                    // Resolve to the nearest meaningful interactive ancestor.
7082                    // Non-interactive elements (bare <div>, <span>, <h2> etc.) are silently
7083                    // ignored — no fallback to event.target.
7084                    var target = findClickTarget(event.target);
7085                    if (!target) return;
7086
7087                    var now = Date.now();
7088                    var st  = rageMap.get(target) || { count: 0, last: 0, timer: null };
7089
7090                    if (now - st.last > RAGE_TIMEOUT) st.count = 0;
7091                    st.count++;
7092                    st.last = now;
7093
7094                    if (st.timer) clearTimeout(st.timer);
7095                    st.timer = setTimeout(function() { rageMap.delete(target); }, RAGE_TIMEOUT);
7096                    rageMap.set(target, st);
7097
7098                    if (st.count >= RAGE_THRESHOLD) {
7099                        rageMap.delete(target);
7100                        var params = describeElement(target); // contains only non-empty fields
7101
7102                        Object.keys(options.dynamicEvents.automatic_event_rage_click).forEach(function(slug) {
7103                            var pysEvent = Utils.clone(options.dynamicEvents.automatic_event_rage_click[slug]);
7104                            Utils.copyProperties(params, pysEvent.params);
7105                            var px = getPixelBySlag(slug);
7106                            if (px) px.fireEvent(pysEvent.name, pysEvent);
7107                        });
7108                    }
7109                }, true);
7110            })();
7111        }
7112
7113        // Global Video Speed tracking
7114        if (options.dynamicEvents.hasOwnProperty('automatic_event_video_speed')) {
7115            (function() {
7116                var pysFireVideoSpeed = function(videoEl, currRate) {
7117                    var html5Url = videoEl ? (videoEl.src || videoEl.currentSrc || '') : '';
7118                    var params = {
7119                        video_url: html5Url,
7120                        video_type: Utils.getVideoTypeFromUrl(html5Url),
7121                        video_title: Utils.getHtml5VideoTitle(html5Url),
7122                        playback_speed: currRate,
7123                        element: videoEl ? (videoEl.tagName ? videoEl.tagName.toLowerCase() : 'video') : 'video'
7124                    };
7125                    Object.keys(options.dynamicEvents.automatic_event_video_speed).forEach(function(slug) {
7126                        var pysEvent = Utils.clone(options.dynamicEvents.automatic_event_video_speed[slug]);
7127                        Utils.copyProperties(params, pysEvent.params);
7128                        var px = getPixelBySlag(slug);
7129                        if (px) px.fireEvent(pysEvent.name, pysEvent);
7130                    });
7131                };
7132
7133                // HTML5 <video>
7134                document.addEventListener('ratechange', function(event) {
7135                    var video = event.target;
7136                    if (!video || video.tagName !== 'VIDEO') return;
7137                    var prev = video._pysGlobalSpeedRate !== undefined ? video._pysGlobalSpeedRate : 1;
7138                    var curr = video.playbackRate;
7139                    if (prev === curr) return;
7140                    video._pysGlobalSpeedRate = curr;
7141                    pysFireVideoSpeed(video, curr);
7142                }, true);
7143            })();
7144        }
7145
7146        // setup WooCommerce events
7147        if (options.woo.enabled) {
7148
7149            // Woo CartFlow AddToCart
7150            if (options.dynamicEvents.hasOwnProperty("wcf_add_to_cart_on_next_step_click")) {
7151                $("body").on("click",'.wcf-next-step-link',function () {
7152                    var pixels = Object.keys(options.dynamicEvents.wcf_add_to_cart_on_next_step_click);
7153                    for(var i = 0;i<pixels.length;i++) {
7154                        var event = Utils.clone(options.dynamicEvents.wcf_add_to_cart_on_next_step_click[pixels[i]])
7155                        getPixelBySlag(pixels[i]).fireEvent(event.name, event);
7156                    }
7157                });
7158            }
7159            // Woo CartFlow Bump AddToCart
7160            if(options.dynamicEvents.hasOwnProperty("wcf_add_to_cart_on_bump_click") ||
7161                options.dynamicEvents.hasOwnProperty("wcf_bump")) {
7162                $("body").on('change','.wcf-bump-order-cb',function () {
7163
7164                    if(this.checked) {
7165                        if(options.dynamicEvents.hasOwnProperty("wcf_add_to_cart_on_bump_click")) {
7166                            var pixels = Object.keys(options.dynamicEvents.wcf_add_to_cart_on_bump_click);
7167                            for(var i = 0;i<pixels.length;i++) {
7168                                var event = Utils.clone(options.dynamicEvents.wcf_add_to_cart_on_bump_click[pixels[i]]);
7169                                getPixelBySlag(pixels[i]).fireEvent(event.name, event);
7170                            }
7171                        }
7172
7173
7174                        if(options.dynamicEvents.hasOwnProperty("wcf_bump")) {
7175                            var pixels = Object.keys(options.dynamicEvents.wcf_bump);
7176                            for(var i = 0;i<pixels.length;i++) {
7177                                var event = Utils.clone(options.dynamicEvents.wcf_bump[pixels[i]]);
7178                                getPixelBySlag(pixels[i]).fireEvent(event.name, event);
7179                            }
7180                        }
7181
7182                    } else {
7183                        if(options.dynamicEvents.hasOwnProperty("wcf_remove_from_cart_on_bump_click")) {
7184                            var pixels = Object.keys(options.dynamicEvents.wcf_remove_from_cart_on_bump_click);
7185                            for(var i = 0;i<pixels.length;i++) {
7186                                var event = Utils.clone(options.dynamicEvents.wcf_remove_from_cart_on_bump_click[pixels[i]]);
7187                                getPixelBySlag(pixels[i]).fireEvent(event.name, event);
7188                            }
7189                        }
7190
7191                    }
7192
7193
7194                });
7195            }
7196
7197
7198            // WooCommerce AddToCart
7199            if (options.dynamicEvents.hasOwnProperty("woo_add_to_cart_on_button_click")
7200                && options.woo.hasOwnProperty("addToCartCatchMethod")
7201                && options.woo.addToCartCatchMethod === "add_cart_js"
7202            ) {
7203                // Loop, any kind of "simple" product, except external
7204                $('.add_to_cart_button:not(.product_type_variable,.product_type_bundle,.single_add_to_cart_button)').on("click",function (e) {
7205
7206                    var $button = $(this);
7207                    var $prod_info = $button.closest('.product').find('.pys_list_name_productdata').data();
7208                    var product_id = $(this).data('product_id');
7209                    Cookies.set('productlist', JSON.stringify($prod_info), { expires: 1,path: '/' })
7210                    var product_id = $(this).data('product_id');
7211                    if (typeof product_id !== 'undefined') {
7212
7213                        if(options.dynamicEvents.hasOwnProperty("woo_add_to_cart_on_button_click")){
7214                            var tmpEventID = pys_generate_token();
7215                            $.each(options.dynamicEvents.woo_add_to_cart_on_button_click, function (i, tag) {
7216                                tag.eventID = tmpEventID;
7217                                // Also refresh the uniqueId cache so server-API path
7218                                // (ajaxForServerStaticEvent) gets the same fresh ID.
7219                                var idKey = tag.hasOwnProperty('custom_event_post_id') ? tag.custom_event_post_id : tag.e_id;
7220                                uniqueId[idKey] = tmpEventID;
7221                            });
7222                        }
7223
7224                        Facebook.onWooAddToCartOnButtonEvent(product_id,$(this));
7225                        Analytics.onWooAddToCartOnButtonEvent(product_id, $prod_info);
7226                        GTM.onWooAddToCartOnButtonEvent(product_id, $prod_info);
7227                        GAds.onWooAddToCartOnButtonEvent(product_id);
7228                        Pinterest.onWooAddToCartOnButtonEvent(product_id);
7229                        Bing.onWooAddToCartOnButtonEvent(product_id);
7230                        TikTok.onWooAddToCartOnButtonEvent(product_id);
7231                        Reddit.onWooAddToCartOnButtonEvent(product_id);
7232                    }
7233
7234                });
7235
7236                // Single Product
7237                // tap try to https://stackoverflow.com/questions/30990967/on-tap-click-event-firing-twice-how-to-avoid-it
7238                //  $(document) not work
7239                $('body').onFirst('click','button.single_add_to_cart_button,.single_add_to_cart_button',function (e) {
7240
7241                    var $button = $(this);
7242                    var $prod_info = $button.siblings('.pys_list_name_productdata').data();
7243                    var product_id = $(this).data('product_id');
7244                    Cookies.set('productlist', JSON.stringify($prod_info), { expires: 1,path: '/' })
7245                    if ($button.hasClass('disabled')) {
7246                        return;
7247                    }
7248
7249                    var $form = $button.closest('form');
7250
7251                    var product_type = Utils.PRODUCT_SIMPLE;
7252                    var is_external = false;
7253
7254                    if ($form.length === 0) {
7255                        is_external = true;
7256                    } else if ($form.hasClass('variations_form')) {
7257                        product_type = Utils.PRODUCT_VARIABLE;
7258                    } else if($form.hasClass('bundle_form')) {
7259                        product_type = Utils.PRODUCT_BUNDLE;
7260                    } else if($form.hasClass('grouped_form')) {
7261                        product_type = Utils.PRODUCT_GROUPED;
7262                    }
7263
7264
7265
7266                    var product_id;
7267                    var qty = 1;
7268                    if (product_type === Utils.PRODUCT_GROUPED) {
7269                        qty = 1;
7270                        product_id = parseInt($form.find('*[name="add-to-cart"]').val());
7271                    } else if (product_type === Utils.PRODUCT_VARIABLE) {
7272                        product_id = parseInt($form.find('*[name="add-to-cart"]').val());
7273                        var qtyTag = $form.find('input[name="quantity"]');
7274                        if(qtyTag.length <= 0) {
7275                            qtyTag = $form.find('select[name="quantity"]');
7276                        }
7277                        qty = parseInt(qtyTag.val());
7278                    } else if (is_external) {
7279                        product_id = options.woo.singleProductId;
7280                        qty = 1;
7281                    } else {
7282                        product_id = parseInt($form.find('*[name="add-to-cart"]').val());
7283                        var qtyTag = $form.find('input[name="quantity"]');
7284                        if(qtyTag.length <= 0) {
7285                            qtyTag = $form.find('select[name="quantity"]');
7286                        }
7287                        qty = parseInt(qtyTag.val());
7288                    }
7289
7290                    //
7291                    if(options.dynamicEvents.hasOwnProperty("woo_add_to_cart_on_button_click")){
7292                        var tmpEventID = pys_generate_token();
7293                        $.each(options.dynamicEvents.woo_add_to_cart_on_button_click, function (i, tag) {
7294                            tag.eventID = tmpEventID;
7295                            // Also refresh the uniqueId cache so server-API path
7296                            // (ajaxForServerStaticEvent) gets the same fresh ID.
7297                            var idKey = tag.hasOwnProperty('custom_event_post_id') ? tag.custom_event_post_id : tag.e_id;
7298                            uniqueId[idKey] = tmpEventID;
7299                        });
7300                    }
7301
7302                    Facebook.onWooAddToCartOnSingleEvent(product_id, qty, product_type, is_external, $form);
7303                    Analytics.onWooAddToCartOnSingleEvent(product_id, qty, product_type, is_external, $form, $prod_info);
7304                    GTM.onWooAddToCartOnSingleEvent(product_id, qty, product_type, is_external, $form, $prod_info);
7305                    GAds.onWooAddToCartOnSingleEvent(product_id, qty, product_type, is_external, $form);
7306                    Pinterest.onWooAddToCartOnSingleEvent(product_id, qty, product_type, is_external, $form);
7307                    Bing.onWooAddToCartOnSingleEvent(product_id, qty, product_type, is_external, $form);
7308                    TikTok.onWooAddToCartOnSingleEvent(product_id, qty, product_type, is_external, $form);
7309                    Reddit.onWooAddToCartOnSingleEvent(product_id, qty, product_type, is_external, $form);
7310                });
7311
7312            } else {
7313                $('.add_to_cart_button:not(.product_type_variable,.product_type_bundle,.single_add_to_cart_button)').on("click",function (e) {
7314                    var $button = $(this);
7315                    var $prod_info = $button.siblings('.pys_list_name_productdata').data();
7316                    var product_id = $(this).data('product_id');
7317                    Cookies.set('productlist', JSON.stringify($prod_info), { expires: 1,path: '/' })
7318                });
7319
7320                // Single Product
7321                // tap try to https://stackoverflow.com/questions/30990967/on-tap-click-event-firing-twice-how-to-avoid-it
7322                //  $(document) not work
7323                $('body').onFirst('click','button.single_add_to_cart_button,.single_add_to_cart_button',function (e) {
7324
7325                    var $button = $(this);
7326                    var $prod_info = $button.siblings('.pys_list_name_productdata').data();
7327                    Cookies.set('productlist', $prod_info, { expires: 1,path: '/' })
7328                });
7329            }
7330
7331            // WooCommerce Affiliate
7332            if (options.dynamicEvents.hasOwnProperty("woo_affiliate")) {
7333
7334                // Loop, external
7335                $('.product_type_external').on("click",function (e) {
7336
7337                    var product_id = $(this).data('product_id');
7338
7339                    if (typeof product_id !== 'undefined') {
7340                        Facebook.onWooAffiliateEvent(product_id);
7341                        Analytics.onWooAffiliateEvent(product_id);
7342                        GTM.onWooAffiliateEvent(product_id);
7343                        GAds.onWooAffiliateEvent(product_id);
7344                        Pinterest.onWooAffiliateEvent(product_id);
7345                        Bing.onWooAffiliateEvent(product_id);
7346                    }
7347
7348                });
7349
7350            }
7351
7352            // WooCommerce RemoveFromCart
7353            if (options.dynamicEvents.hasOwnProperty("woo_remove_from_cart")) {
7354
7355                $('body').on('click', options.woo.removeFromCartSelector, function (e) {
7356
7357                    var $a = $(e.currentTarget),
7358                        href = $a.attr('href');
7359
7360                    // extract cart item hash from remove button URL
7361                    var regex = new RegExp("[\\?&]remove_item=([^&#]*)"),
7362                        results = regex.exec(href);
7363
7364                    if (results !== null) {
7365
7366                        var item_hash = results[1];
7367
7368                        if (options.dynamicEvents["woo_remove_from_cart"].hasOwnProperty(item_hash)) {
7369                            var events = options.dynamicEvents["woo_remove_from_cart"][item_hash];
7370                            
7370Utils.fireEventForAllPixel("onWooRemoveFromCartEvent",events)
7371                        }
7372
7373                    }
7374
7375                });
7376
7377            }
7378
7379            // WooCommerce PayPal
7380            if (options.dynamicEvents.hasOwnProperty("woo_paypal")) {
7381
7382                // Non-default binding used to avoid situations when some code in external js
7383                // stopping events propagation, eg. returns false, and our handler will never called
7384                $(document).onFirst('submit click', '#place_order', function (e) {
7385
7386                    var method = $('form[name="checkout"] input[name="payment_method"]:checked').val();
7387
7388                    if (method !== 'paypal') {
7389                        return;
7390                    }
7391                    var events = options.dynamicEvents.woo_paypal;
7392                    Utils.fireEventForAllPixel("onWooPayPalEvent",events)
7393
7394                });
7395
7396            }
7397
7398            // WooCommerce checkout progress
7399            if(options.dynamicEvents.hasOwnProperty("woo_initiate_checkout_progress_f") ) {
7400
7401                $(document).on("change",".woocommerce-validated #billing_first_name",function () {
7402                    var pixels = Object.keys(options.dynamicEvents.woo_initiate_checkout_progress_f);
7403                    for (var i = 0; i < pixels.length; i++) {
7404                        var event = Utils.clone(options.dynamicEvents.woo_initiate_checkout_progress_f[pixels[i]]);
7405                        getPixelBySlag(pixels[i]).onWooCheckoutProgressStep(event);
7406                    }
7407                });
7408            }
7409            if(options.dynamicEvents.hasOwnProperty("woo_initiate_checkout_progress_l")) {
7410
7411                $(document).on("change",".woocommerce-validated #billing_last_name",function () {
7412                    var pixels = Object.keys(options.dynamicEvents.woo_initiate_checkout_progress_l);
7413                    for (var i = 0; i < pixels.length; i++) {
7414                        var event = Utils.clone(options.dynamicEvents.woo_initiate_checkout_progress_l[pixels[i]]);
7415                        getPixelBySlag(pixels[i]).onWooCheckoutProgressStep(event);
7416                    }
7417                });
7418            }
7419
7420            if(options.dynamicEvents.hasOwnProperty("woo_initiate_checkout_progress_e")) {
7421
7422                $(document).on("change",".woocommerce-validated #billing_email",function () {
7423                    var pixels = Object.keys(options.dynamicEvents.woo_initiate_checkout_progress_e);
7424                    for (var i = 0; i < pixels.length; i++) {
7425                        var event = Utils.clone(options.dynamicEvents.woo_initiate_checkout_progress_e[pixels[i]]);
7426                        getPixelBySlag(pixels[i]).onWooCheckoutProgressStep(event);
7427                    }
7428                });
7429            }
7430            if(options.dynamicEvents.hasOwnProperty("woo_initiate_checkout_progress_o")) {
7431                $(document).onFirst('submit click', '#place_order', function () {
7432                    var shippingMethodFull = $('[name="shipping_method[0]"]:checked').val();
7433                    var shippingMethod = shippingMethodFull ? shippingMethodFull.split(':')[0] : '';
7434                    var pixels = Object.keys(options.dynamicEvents.woo_initiate_checkout_progress_o);
7435                    for (var i = 0; i < pixels.length; i++) {
7436                        var event = Utils.clone(options.dynamicEvents.woo_initiate_checkout_progress_o[pixels[i]]);
7437                        // Add shipping_method to event params
7438                        event.params = event.params || {};
7439                        event.params.checkout_option = shippingMethod;
7440                        getPixelBySlag(pixels[i]).onWooCheckoutProgressStep(event);
7441                    }
7442                });
7443            }
7444
7445
7446            // WooCommerce
7447
7448            $('.product.type-product a.woocommerce-loop-product__link').onFirst('click', function (evt) {
7449                var productId = $(this).closest('.product').find(".add_to_cart_button").attr("data-product_id");
7450                var eventTypes = ["woo_select_content_search", "woo_select_content_shop", "woo_select_content_tag", "woo_select_content_single", "woo_select_content_category"];
7451                var isEventFired = false;
7452
7453                for (var i = 0; i < eventTypes.length; i++) {
7454                    var eventType = eventTypes[i];
7455                    if (options.dynamicEvents.hasOwnProperty(eventType) && options.dynamicEvents[eventType].hasOwnProperty(productId)) {
7456                        if(Analytics.isEnabled()){
7457                            Analytics.onWooSelectContent(options.dynamicEvents[eventType][productId][Analytics.tag()]);
7458                        }
7459                        if(GTM.isEnabled()){
7460                            GTM.onWooSelectContent(options.dynamicEvents[eventType][productId][GTM.tag()]);
7461                        }
7462                        isEventFired = true;
7463                        break;
7464                    }
7465                }
7466
7467                if (!isEventFired) {
7468                    let prod_info = $(this).parent().find('.pys_list_name_productdata').data();
7469                    if (prod_info) {
7470                        const select_prod_list = {};
7471                        if (prod_info['pys_list_name_productlist_name']) {
7472                            select_prod_list.list_name = prod_info['pys_list_name_productlist_name']
7473                        }
7474                        if (prod_info['pys_list_name_productlist_id']) {
7475                            select_prod_list.list_id = prod_info['pys_list_name_productlist_id']
7476                        }
7477                        const url = new URL(window.location.href);
7478                        select_prod_list.url = url.origin + url.pathname;
7479                        Cookies.set('select_prod_list', JSON.stringify(select_prod_list), { expires: 1,path: '/' });
7480                    }
7481                }
7482            });
7483
7484        }
7485
7486        // setup EDD events
7487        if (options.edd.enabled) {
7488
7489            // EDD AddToCart
7490            if (options.dynamicEvents.hasOwnProperty("edd_add_to_cart_on_button_click")) {
7491
7492                $('form.edd_download_purchase_form .edd-add-to-cart').on("click",function (e) {
7493
7494                    var $button = $(this);
7495                    var $form = $button.closest('form');
7496                    var variable_price = $button.data('variablePrice'); // yes/no
7497                    var price_mode = $button.data('priceMode'); // single/multi
7498                    var ids = [];
7499                    var quantities = [];
7500                    var qty;
7501                    var id;
7502
7503                    if (variable_price === 'yes' && price_mode === 'multi') {
7504
7505                        id = $form.find('input[name="download_id"]').val();
7506
7507                        // get selected variants
7508                        $.each($form.find('input[name="edd_options[price_id][]"]:checked'), function (i, el) {
7509                            ids.push(id + '_' + $(el).val());
7510                        });
7511
7512                        // get qty for selected variants
7513                        $.each(ids, function (i, variant_id) {
7514
7515                            var variant_index = variant_id.split('_', 2);
7516                            qty = $form.find('input[name="edd_download_quantity_' + variant_index[1] + '"]').val();
7517
7518                            if (typeof qty !== 'undefined') {
7519                                quantities.push(qty);
7520                            } else {
7521                                quantities.push(1);
7522                            }
7523
7524                        });
7525
7526                    } else if (variable_price === 'yes' && price_mode === 'single') {
7527
7528                        id = $form.find('input[name="download_id"]').val();
7529                        ids.push(id + '_' + $form.find('input[name="edd_options[price_id][]"]:checked').val());
7530
7531                        qty = $form.find('input[name="edd_download_quantity"]').val();
7532
7533                        if (typeof qty !== 'undefined') {
7534                            quantities.push(qty);
7535                        } else {
7536                            quantities.push(1);
7537                        }
7538
7539                    } else {
7540
7541                        ids.push($button.data('downloadId'));
7542
7543                        qty = $form.find('input[name="edd_download_quantity"]').val();
7544
7545                        if (typeof qty !== 'undefined') {
7546                            quantities.push(qty);
7547                        } else {
7548                            quantities.push(1);
7549                        }
7550                    }
7551
7552                    // fire event for each download/variant
7553                    $.each(ids, function (i, download_id) {
7554
7555                        var q = parseInt(quantities[i]);
7556                        var variant_index = download_id.toString().split('_', 2);
7557                        var price_index;
7558
7559                        if (variant_index.length === 2) {
7560                            download_id = variant_index[0];
7561                            price_index = variant_index[1];
7562                        }
7563
7564                        Facebook.onEddAddToCartOnButtonEvent(download_id, price_index, q);
7565                        Analytics.onEddAddToCartOnButtonEvent(download_id, price_index, q);
7566                        GTM.onEddAddToCartOnButtonEvent(download_id, price_index, q);
7567                        GAds.onEddAddToCartOnButtonEvent(download_id, price_index, q);
7568                        Pinterest.onEddAddToCartOnButtonEvent(download_id, price_index, q);
7569                        Bing.onEddAddToCartOnButtonEvent(download_id, price_index, q);
7570                        TikTok.onEddAddToCartOnButtonEvent(download_id, price_index, q);
7571                        Reddit.onEddAddToCartOnButtonEvent(download_id, price_index, q);
7572
7573                    });
7574
7575                });
7576
7577            }
7578
7579            // EDD RemoveFromCart
7580            if (options.dynamicEvents.hasOwnProperty("edd_remove_from_cart") ) {
7581
7582                $('form#edd_checkout_cart_form .edd_cart_remove_item_btn').on("click",function (e) {
7583
7584                    var href = $(this).attr('href');
7585                    var key = href.substring(href.indexOf('=') + 1).charAt(0);
7586
7587                    if (options.dynamicEvents.edd_remove_from_cart.hasOwnProperty(key)) {
7588                        var events = options.dynamicEvents.edd_remove_from_cart[key];
7589                        Utils.fireEventForAllPixel("onEddRemoveFromCartEvent",events)
7590                    }
7591
7592                });
7593
7594            }
7595
7596        }
7597
7598        Utils.setupURLClickEvents();
7599
7600        // setup Comment Event
7601        if (options.dynamicEvents.hasOwnProperty("automatic_event_comment")
7602        ) {
7603
7604            $('form.comment-form').on("submit",function () {
7605                if (options.dynamicEvents.hasOwnProperty("automatic_event_comment")) {
7606                    var pixels = Object.keys(options.dynamicEvents.automatic_event_comment);
7607                    for (var i = 0; i < pixels.length; i++) {
7608                        var event = Utils.clone(options.dynamicEvents.automatic_event_comment[pixels[i]]);
7609                        if ( pixels[i] !== 'tiktok' && pixels[i] !== 'reddit') {
7610                            Utils.copyProperties(Utils.getRequestParam
7610s(), event.params);
7611                        }
7612                        getPixelBySlag(pixels[i]).onCommentEvent(event);
7613                    }
7614                }
7615            });
7616
7617        }
7618
7619        // setup Form Event
7620        if ( options.dynamicEvents.hasOwnProperty("automatic_event_form")) {
7621
7622            $(document).onFirst('submit', 'form', function (e) {
7623
7624                var $form = $(this);
7625
7626                // exclude WP forms
7627                const formClass = $form.attr('class') || '';
7628                const formRole = ($form.attr('role') || '').toLowerCase();
7629                const formId = $form.attr('id');
7630
7631                if (
7632                    $form.hasClass('comment-form') ||
7633                    $form.hasClass('search-form') ||
7634                    $form.hasClass('woocommerce-ordering') ||
7635                    formClass.toLowerCase().includes('search') || formClass.toLowerCase().includes('add-to-cart') ||
7636                    formRole === 'search' ||
7637                    formId === 'adminbarsearch'
7638                ) {
7639                    return;
7640                }
7641
7642                // exclude Woo forms
7643                if ($form.hasClass('woocommerce-product-search') || $form.hasClass('cart') || $form.hasClass('woocommerce-cart-form') ||
7644                    $form.hasClass('woocommerce-shipping-calculator') || $form.hasClass('checkout') || $form.hasClass('checkout_coupon')) {
7645                    return;
7646                }
7647
7648                // exclude EDD forms
7649                if ($form.hasClass('edd_form') || $form.hasClass('edd_download_purchase_form')) {
7650                    return;
7651                }
7652                // exclude CF7 forms
7653                if ($form.hasClass('wpcf7-form')) {
7654                    return;
7655                }
7656                // exclude Gravity forms
7657                if ($form.attr('id') && $form.attr('id').includes('gform')) {
7658                    var target = $form.attr('target');
7659                    if (target && target.indexOf('gform_ajax_frame') !== -1) {
7660                        return;
7661                    }
7662                }
7663                // exclude Forminator forms
7664                if ($form.hasClass('forminator-custom-form') || $form.hasClass('forminator_ajax')) {
7665                    return;
7666                }
7667                // exclude WPforms forms
7668                if ($form.hasClass('wpforms-form') || $form.hasClass('wpforms-ajax-form')) {
7669                    return;
7670                }
7671                // exclude Formidable forms
7672                /*if ($form.hasClass('frm-show-form')) {
7673                    return;
7674                }*/
7675                // exclude Ninja Forms forms
7676                if ($form.parent().hasClass('nf-form-layout')) {
7677                    return;
7678                }
7679                // exclude Fluent forms
7680                if ($form.hasClass('frm-fluent-form')) {
7681                    return;
7682                }
7683
7684                // exclude WS form forms
7685                if ($form.hasClass('wsf-form') ) {
7686                    return;
7687                }
7688
7689                // exclude WS form forms
7690                if ( $form.hasClass( 'elementor-form' ) ) {
7691                    return;
7692                }
7693
7694                if(!options.enable_success_send_form) {
7695                    var params = {
7696                        form_id: $form.attr('id'),
7697                        form_class: $form.attr('class') ? $form.attr('class') : $form.attr('id'),
7698                        text: $form.find('[type="submit"]').is('input') ?
7699                            $form.find('[type="submit"]').val() : $form.find('[type="submit"]').text()
7700                    };
7701
7702                    if (options.dynamicEvents.hasOwnProperty("automatic_event_form")) {
7703                        var pixels = Object.keys(options.dynamicEvents.automatic_event_form);
7704                        for (var i = 0; i < pixels.length; i++) {
7705                            var event = Utils.clone(options.dynamicEvents.automatic_event_form[pixels[i]]);
7706
7707                            if (pixels[i] === "tiktok" || pixels[i] === "reddit") {
7708                                getPixelBySlag(pixels[i]).fireEvent(event.name, event);
7709                            } else {
7710                                Utils.copyProperties(params, event.params,)
7711                                Utils.copyProperties(Utils.getRequestParam
7711s(), event.params);
7712                                getPixelBySlag(pixels[i]).onFormEvent(event);
7713                            }
7714                        }
7715                    }
7716                }
7717            });
7718
7719
7720        }
7721
7722        jQuery(document).on('elementor/popup/show', function(event) {
7723            for (var i = 0; i < jQuery(".wpcf7-form").length; i++) {
7724                wpcf7.init(jQuery(".wpcf7-form")[i]);
7725            }
7726        });
7727
7728        document.addEventListener( 'wpcf7mailsent', function ( event ) {
7729            let form_id = event.detail.contactFormId,
7730                sendEventId = null,
7731                disabled_form_action = false,
7732                form_submit_mode = 'both';
7733            if ( options.triggerEventTypes.hasOwnProperty( 'CF7' ) ) {
7734                $.each( options.triggerEventTypes.CF7, function ( eventId, triggers ) {
7735                    $.each( triggers, function ( index, trigger ) {
7736                        $.each( trigger.forms, function ( i, value ) {
7737                            if ( value == form_id ) {
7738                                sendEventId = eventId;
7739                                disabled_form_action = trigger.disabled_form_action;
7740                                form_submit_mode = trigger.form_submit_mode || 'both';
7741                            }
7742                        } )
7743                    } );
7744                } );
7745            }
7746            if ( sendEventId != null && ( form_submit_mode === 'both' || form_submit_mode === 'ajax_only' ) ) {
7747                Utils.handleTriggerFired( sendEventId, 'CF7' );
7748            }
7749            sendFormAction( $( event.target ), form_id, sendEventId, disabled_form_action, form_submit_mode );
7750
7751        }, false );
7752
7753        //GravityForm
7754        jQuery( document ).on( 'gform_confirmation_loaded', function ( event, formId ) {
7755            let form_id = formId,
7756                sendEventId = null,
7757                disabled_form_action = false,
7758                form_submit_mode = 'both';
7759            if ( options.triggerEventTypes.hasOwnProperty( 'gravity' ) ) {
7760                $.each( options.triggerEventTypes.gravity, function ( eventId, triggers ) {
7761                    $.each( triggers, function ( index, trigger ) {
7762                        $.each( trigger.forms, function ( i, value ) {
7763                            if ( value == form_id ) {
7764                                disabled_form_action = trigger.disabled_form_action;
7765                                sendEventId = eventId;
7766                                form_submit_mode = trigger.form_submit_mode || 'both';
7767                            }
7768                        } )
7769                    } );
7770                } );
7771            }
7772
7773            if ( sendEventId != null && ( form_submit_mode === 'both' || form_submit_mode === 'ajax_only' ) ) {
7774                Utils.handleTriggerFired( sendEventId, 'gravity' );
7775            }
7776            sendFormAction( $( event.target ), form_id, sendEventId, disabled_form_action, form_submit_mode );
7777            jQuery( document ).off( 'gform_confirmation_loaded' );
7778        } );
7779        //Forminator
7780        $( document ).on( 'forminator:form:submit:success', function ( event ) {
7781
7782            let form_id = $( event.target ).find( 'input[name="form_id"]' ).val(),
7783                sendEventId = null,
7784                disabled_form_action = false,
7785                form_submit_mode = 'both';
7786            if ( options.triggerEventTypes.hasOwnProperty( 'forminator' ) ) {
7787                $.each( options.triggerEventTypes.forminator, function ( eventId, triggers ) {
7788                    $.each( triggers, function ( index, trigger ) {
7789                        $.each( trigger.forms, function ( i, value ) {
7790                            if ( value == form_id ) {
7791                                disabled_form_action = trigger.disabled_form_action;
7792                                sendEventId = eventId;
7793                                form_submit_mode = trigger.form_submit_mode || 'both';
7794                            }
7795                        } )
7796                    } );
7797                } );
7798            }
7799            if ( sendEventId != null && ( form_submit_mode === 'both' || form_submit_mode === 'ajax_only' ) ) {
7800                Utils.handleTriggerFired( sendEventId, 'forminator' );
7801            }
7802            sendFormAction( $( event.target ), form_id, sendEventId, disabled_form_action, form_submit_mode );
7803        } );
7804
7805        //WPForm
7806        $( 'form.wpforms-form' ).on( 'wpformsAjaxSubmitSuccess', ( event ) => {
7807
7808            let form_id = $( event.target ).attr( 'data-formid' ),
7809                sendEventId = null,
7810                disabled_form_action = false,
7811                form_submit_mode = 'both';
7812
7813            if ( options.triggerEventTypes.hasOwnProperty( 'wpforms' ) ) {
7814                $.each( options.triggerEventTypes.wpforms, function ( eventId, triggers ) {
7815                    $.each( triggers, function ( index, trigger ) {
7816                        $.each( trigger.forms, function ( i, value ) {
7817                            if ( value == form_id ) {
7818                                sendEventId = eventId;
7819                                disabled_form_action = trigger.disabled_form_action;
7820                                form_submit_mode = trigger.form_submit_mode || 'both';
7821                            }
7822                        } )
7823                    } );
7824                } );
7825            }
7826            if ( sendEventId != null && ( form_submit_mode === 'both' || form_submit_mode === 'ajax_only' ) ) {
7827                Utils.handleTriggerFired( sendEventId, 'wpforms' );
7828            }
7829            sendFormAction( $( event.target ), form_id, sendEventId, disabled_form_action, form_submit_mode );
7830        } )
7831
7832        $( document ).on( 'frmFormComplete', function ( event, form, response ) {
7833            const form_id = $( form ).find( 'input[name="form_id"]' ).val();
7834            let sendEventId = null,
7835                disabled_form_action = false,
7836                form_submit_mode = 'both';
7837            if ( options.triggerEventTypes.hasOwnProperty( 'formidable' ) ) {
7838                $.each( options.triggerEventTypes.formidable, function ( eventId, triggers ) {
7839                    $.each( triggers, function ( index, trigger ) {
7840                        $.each( trigger.forms, function ( i, value ) {
7841                            if ( value == form_id ) {
7842                                disabled_form_action = trigger.disabled_form_action;
7843                                sendEventId = eventId;
7844                                form_submit_mode = trigger.form_submit_mode || 'both';
7845                            }
7846                        } )
7847                    } );
7848                } );
7849            }
7850            if ( sendEventId != null && ( form_submit_mode === 'both' || form_submit_mode === 'ajax_only' ) ) {
7851                Utils.handleTriggerFired( sendEventId, 'formidable' );
7852            }
7853            sendFormAction( $( event.target ), form_id, sendEventId, disabled_form_action, form_submit_mode );
7854
7855        } );
7856
7857        // Ninja Forms
7858        $( document ).onFirst( 'nfFormSubmitResponse', function ( event, data ) {
7859            const form_id = data.response.data.form_id;
7860            let sendEventId = null,
7861                disabled_form_action = false,
7862                form_submit_mode = 'both';
7863            if ( options.triggerEventTypes.hasOwnProperty( 'ninjaform' ) ) {
7864                $.each( options.triggerEventTypes.ninjaform, function ( eventId, triggers ) {
7865                    $.each( triggers, function ( index, trigger ) {
7866                        $.each( trigger.forms, function ( i, value ) {
7867                            if ( value == form_id ) {
7868                                disabled_form_action = trigger.disabled_form_action;
7869                                sendEventId = eventId;
7870                                form_submit_mode = trigger.form_submit_mode || 'both';
7871                            }
7872                        } )
7873                    } );
7874                } );
7875            }
7876            if ( sendEventId != null && ( form_submit_mode === 'both' || form_submit_mode === 'ajax_only' ) ) {
7877                Utils.handleTriggerFired( sendEventId, 'ninjaform' );
7878            }
7879            sendFormAction( $( event.target ), form_id, sendEventId, disabled_form_action, form_submit_mode );
7880        } );
7881
7882
7883        $(document).on('fluentform_submission_success', function ( event, data ) {
7884            if(!data || !data.form){
7885                return;
7886            }
7887            let $form = data.form; // Submitted form
7888            let config = data.config; // Form configuration
7889            let response = data.response; // Server response
7890
7891
7892            let $formItem = $form;
7893            let form_id = config.id;
7894            let sendEventId = null,
7895                disabled_form_action = false,
7896                form_submit_mode = 'both';
7897            if ( options.triggerEventTypes.hasOwnProperty( 'fluentform' ) ) {
7898                $.each( options.triggerEventTypes.fluentform, function ( eventId, triggers ) {
7899                    $.each( triggers, function ( index, trigger ) {
7900                        $.each( trigger.forms, function ( i, value ) {
7901                            if ( value == form_id ) {
7902                                disabled_form_action = trigger.disabled_form_action;
7903                                sendEventId = eventId;
7904                                form_submit_mode = trigger.form_submit_mode || 'both';
7905                            }
7906                        } )
7907                    } );
7908                } );
7909            }
7910
7911            if ( sendEventId != null && ( form_submit_mode === 'both' || form_submit_mode === 'ajax_only' ) ) {
7912                Utils.handleTriggerFired( sendEventId, 'fluentform' );
7913            }
7914            sendFormAction( $( event.target ), form_id, sendEventId, disabled_form_action, form_submit_mode );
7915        } );
7916
7917        //WSForm
7918        $( document ).on( 'wsf-submit-complete', ( event, form_object, form_id ) => {
7919            let sendEventId = null,
7920                disabled_form_action = false,
7921                form_submit_mode = 'both';
7922            if ( options.triggerEventTypes.hasOwnProperty( 'wsform' ) ) {
7923                $.each( options.triggerEventTypes.wsform, function ( eventId, triggers ) {
7924                    $.each( triggers, function ( index, trigger ) {
7925                        $.each( trigger.forms, function ( i, value ) {
7926                            if ( value == form_id ) {
7927                                disabled_form_action = trigger.disabled_form_action;
7928                                sendEventId = eventId;
7929                                form_submit_mode = trigger.form_submit_mode || 'both';
7930                            }
7931                        } )
7932                    } );
7933                } );
7934            }
7935
7936            if ( sendEventId != null && ( form_submit_mode === 'both' || form_submit_mode === 'ajax_only' ) ) {
7937                Utils.handleTriggerFired( sendEventId, 'wsform' );
7938            }
7939            sendFormAction( $( event.target ), form_id, sendEventId, disabled_form_action, form_submit_mode );
7940        } )
7941
7942        // Elementor Forms
7943        let forms = document.querySelectorAll( '.elementor-form' );
7944        // Apply the observer to each form
7945        forms.forEach( function ( form ) {
7946            observeElementorForm( form );
7947        } );
7948
7949        // watching Elementor Popup forms
7950        let observer = new MutationObserver( function ( mutationsList, observer ) {
7951            for ( let i = 0; i < mutationsList.length; i++ ) {
7952                let popupForm = document.querySelector( '[class*="elementor-popup"] form' );
7953                if ( popupForm ) {
7954                    observeElementorForm( popupForm );
7955                    observer.disconnect();
7956                    break;
7957                }
7958            }
7959        } );
7960        observer.observe( document.body, { childList: true, subtree: true } );
7961
7962        // load pixel APIs
7963        Utils.loadPixels();
7964
7965        // setup Enrich content
7966        if(Utils.isCheckoutPage()) {
7967            Utils.addCheckoutFields();
7968        }
7969        if(options.woo.hasOwnProperty('woo_view_content_variation_is_selected') && options.woo.woo_view_content_variation_is_selected) {
7970            handleWooViewContentVariation()
7971        }
7972    }
7973
7974    $(document).ready(function () {
7975        if ( options.dynamicDataUrl ) {
7976            fetch( options.dynamicDataUrl, {
7977                method: 'GET',
7978                credentials: 'same-origin',
7979                cache: 'no-store',
7980                headers: { 'Accept': 'application/json' }
7981            } )
7982            .then( function(r) { return r.ok ? r.json() : Promise.reject(r.status); } )
7983            .then( function(dynamic) {
7984                options.ajax_event         = dynamic.ajax_event;
7985                options.user_id            = dynamic.user_id;
7986                options.cache_bypass       = dynamic.cache_bypass;
7987                options.tracking_analytics = dynamic.tracking_analytics;
7988                if ( dynamic.gdpr_dynamic && options.gdpr ) {
7989                    Object.assign( options.gdpr, dynamic.gdpr_dynamic );
7990                    if ( dynamic.gdpr_dynamic.analytics_storage_value !== null )
7991                        options.gdpr.analytics_storage.value = dynamic.gdpr_dynamic.analytics_storage_value;
7992                    if ( dynamic.gdpr_dynamic.ad_storage_value !== null )
7993                        options.gdpr.ad_storage.value = dynamic.gdpr_dynamic.ad_storage_value;
7994                    if ( dynamic.gdpr_dynamic.ad_user_data_value !== null )
7995                        options.gdpr.ad_user_data.value = dynamic.gdpr_dynamic.ad_user_data_value;
7996                    if ( dynamic.gdpr_dynamic.ad_personalization_value !== null )
7997                        options.gdpr.ad_personalization.value = dynamic.gdpr_dynamic.ad_personalization_value;
7998                }
7999                options.cookie = dynamic.cookie;
8000                pysNormalInit();
8001            } )
8002            .catch( function(err) {
8003                if ( options.debug ) console.warn( '[PYS] dynamic-options fetch failed:', err );
8004                pysNormalInit();
8005            } );
8006        } else {
8007            pysNormalInit();
8008        }
8009    });
8010
8011
8012    function handleWooViewContentVariation() {
8013        var form = $('form.variations_form');
8014
8015        form.on('change', 'select', function() {
8016            var selectedAttributes = {};
8017            form.find('select').each(function() {
8018                var attributeName = $(this).data('attribute_name') || $(this).attr('name');
8019                var attributeValue = $(this).val();
8020                if (attributeValue) {
8021                    selectedAttributes[attributeName] = attributeValue;
8022                }
8023            });
8024
8025            $.ajax({
8026                url: options.ajaxUrl,
8027                type: 'POST',
8028                data: {
8029                    action: 'get_variation_info',
8030                    product_id: form.data('product_id'), // Pass the main product ID
8031                    attributes: selectedAttributes
8032                },
8033                success: function(response) {
8034                    if (response.success) {
8035                        $.each(response.data, function(slug) {
8036                            $.each(response.data[slug], function(index, event) {
8037                                event.isVariationTrigger = true;
8038                                getPixelBySlag(slug).fireEvent(event.name, event);
8039                            });
8040                        });
8041                    } else {
8042                        console.log('Error retrieving data:', response.data);
8043                    }
8044                }
8045            });
8046        });
8047    }
8048    var sendFormAction = function (form_target, formId, customEventId = null, disabled = false, form_submit_mode = 'both'){
8049        // Check submit mode - skip automatic event if reload_only
8050        if (disabled == true || form_submit_mode === 'reload_only' ) {
8051            return;
8052        }
8053        
8054        var params = {
8055            form_id: formId,
8056            text: form_target.find('[type="submit"]').is('input') ? form_target.find('[type="submit"]').val() :
8057                form_target.find('.forminator-button-submit').text() != '' ? form_target.find('.forminator-button-submit').text() :
8058                    form_target.find('[type="submit"]').text()
8059        };
8060
8061        if (options.dynamicEvents.hasOwnProperty("automatic_event_form")) {
8062            var pixels = Object.keys(options.dynamicEvents.automatic_event_form);
8063            for (var i = 0; i < pixels.length; i++) {
8064
8065                if ( disabled && customEventId && typeof options.triggerEvents[customEventId][pixels[i]] !== 'undefined') {
8066                    continue;
8067                }
8068                var event = options.dynamicEvents.automatic_event_form[pixels[i]];
8069                if (pixels[i] === "tiktok" || pixels[i] === "reddit") {
8070                    getPixelBySlag(pixels[i]).fireEvent(event.name, event);
8071                } else {
8072                    Utils.copyProperties(params, event.params)
8073                    Utils.copyProperties(Utils.getRequestParams(), event.params);
8074                    getPixelBySlag(pixels[i]).onFormEvent(event);
8075                }
8076            }
8077        }
8078    }
8079
8080    var setupEmailLinks = function ( disabled_for_pixels = [] ) {
8081        if ( options.dynamicEvents.hasOwnProperty( "automatic_event_email_link" ) ) {
8082            var pixels = Object.keys( options.dynamicEvents.automatic_event_email_link );
8083            for ( var i = 0; i < pixels.length; i++ ) {
8084                if ( disabled_for_pixels.indexOf(pixels[ i ]) === -1 ) {
8085                    var event = Utils.clone( options.dynamicEvents.automatic_event_email_link[ pixels[ i ] ] );
8086                    if ( pixels[ i ] !== 'tiktok' && pixels[ i ] !== 'reddit' ) {
8087                        Utils.copyProperties( Utils.getRequestParams(), event.params );
8088                    }
8089                    getPixelBySlag( pixels[ i ] ).fireEvent( event.name, event );
8090                }
8091            }
8092        }
8093    }
8094
8095    //Elementor Forms Observer
8096    var observeElementorForm = function ( form ) {
8097        let observer = new MutationObserver( function ( mutations ) {
8098
8099            for ( let i = 0; i < mutations.length; i++ ) {
8100                let mutation = mutations[ i ];
8101
8102                if ( mutation.type === 'childList' || mutation.type === 'attributes' ) {
8103                    if ( $( form ).find( '.elementor-message-success' ).length > 0 ) {
8104
8105                        let form_id = $( form ).attr( 'id' );
8106                        if ( !form_id ) {
8107                            form_id = $( form ).find( 'input[name="form_id"]' ).val();
8108                        }
8109
8110                        let sendEventId = null,
8111                            disabled_form_action = false,
8112                            form_submit_mode = 'both';
8113                        if ( options.triggerEventTypes.hasOwnProperty( 'elementor_form' ) ) {
8114                            $.each( options.triggerEventTypes.elementor_form, function ( eventId, triggers ) {
8115                                $.each( triggers, function ( index, trigger ) {
8116                                    $.each( trigger.forms, function ( i, value ) {
8117                                        if ( value == form_id ) {
8118                                            disabled_form_action = trigger.disabled_form_action;
8119                                            sendEventId = eventId;
8120                                            form_submit_mode = trigger.form_submit_mode || 'both';
8121                                        }
8122                                    })
8123                                } );
8124                            } );
8125                        }
8126                        if ( sendEventId != null && ( form_submit_mode === 'both' || form_submit_mode === 'ajax_only' ) ) {
8127                            Utils.handleTriggerFired( sendEventId, 'elementor_form' );
8128                        }
8129                        sendFormAction( $( event.target ), form_id, sendEventId, disabled_form_action, form_submit_mode );
8130
8131                        observer.disconnect();
8132                        break;
8133                    }
8134                }
8135            }
8136        } );
8137
8138        // Start observing the form for changes
8139        observer.observe( form, {
8140            attributes: true,
8141            childList: true,
8142            subtree: true
8143        } );
8144    }
8145
8146}(jQuery, pysOptions);
8147
8148
8149function pys_generate_token() {
8150    return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
8151        (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
8152    );
8153}
8154function getBundlePriceOnSingleProduct(data) {
8155    var items_sum = 0;
8156    jQuery(".bundle_form .bundled_product").each(function(index){
8157        var id = jQuery(this).find(".cart").data("bundled_item_id");
8158        var item_price = data.prices[id];
8159        var item_quantity = jQuery(this).find(".bundled_qty").val();
8160        if(!jQuery(this).hasClass("bundled_item_optional") ||
8161            jQuery(this).find(".bundled_product_optional_checkbox input").prop('checked')) {
8162            items_sum += item_price*item_quantity;
8163        }
8164    });
8165    return items_sum;
8166}
8167function getUrlParameter(sParam) {
8168    var sPageURL = window.location.search.substring(1),
8169        sURLVariables = sPageURL.split('&'),
8170        sParameterName,
8171        i;
8172
8173    for (i = 0; i < sURLVariables.length; i++) {
8174        sParameterName = sURLVariables[i].split('=');
8175
8176        if (sParameterName[0] === sParam) {
8177            return sParameterName[1] === undefined ? true : decodeURIComponent(sParameterName[1]);
8178        }
8179    }
8180    return false;
8181};
8182function inArray(needle, haystack) {
8183    var length = haystack.length;
8184    for(var i = 0; i < length; i++) {
8185        if(haystack[i] == needle) return true;
8186    }
8187    return false;
8188}
8189
8190function getCookieYes(key) {
8191    const cookiesObj = document.cookie
8192        .split(";")
8193        .reduce((ac, cv) => {
8194            const [k, v] = cv.split("=");
8195            if (k && v) ac[k.trim()] = v;
8196            return ac;
8197        }, {});
8198    const consentCookie = cookiesObj["cookieyes-consent"] || cookiesObj["wt_consent"];
8199    if (!consentCookie) return undefined;
8200    const { [key]: value } = consentCookie
8201        .split(",")
8202        .reduce((obj, pair) => {
8203            const [k, v] = pair.split(":");
8204            if (k && v) obj[k] = v;
8205            return obj;
8206        }, {});
8207    return value;
8208}
8209
8210function getRootDomain(useSubdomain = false) {
8211    const hostname = window.location.hostname; // Get the current hostname
8212    // Check if tldjs is defined before using it
8213    if (typeof tldjs === "undefined") {
8214        console.warn("tldjs is not defined");
8215        return hostname; // Return hostname as a fallback
8216    }
8217
8218    const rootDomain = tldjs.getDomain(hostname); // Use tldjs to extract the root domain
8219
8220    // Return the root domain with or without a leading dot based on useSubdomain
8221    return rootDomain ? (useSubdomain ? '.' + rootDomain : rootDomain) : hostname;
8222}

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.