PageSourceSearch

https://smartvan.com.br/wp-content/plugins/pixelyoursite/dist/scripts/public.js?ver=11.2.1

js smartvan.com.br collected 2026-10-01 14:26:08 UTC 172,979 bytes, 4,087 lines download raw bytes

1/* global pysOptions */
2
3
4! function ($, options) {
5    if (options.debug) {
6        console.log('PYS:', options);
7    }
8    var uniqueId = {};
9
10    let gtm_variables = {};
11    let gtm_datalayername = "dynamicVariable";
12
13    var domain = '';
14    if(options.hasOwnProperty("track_cookie_for_subdomains") && options.track_cookie_for_subdomains) {
15        domain = getRootDomain(true);
16    }
17
18    // Per-page referrer for Facebook CAPI events. Captured once per script
19    // load so SPA-style navigations within the same HTML document do not
20    // overwrite it. Internal/external is NOT filtered — Meta expects this
21    // field to describe the URL of the previous page for THIS event.
22    var pageReferrer = '';
23    try {
24        pageReferrer = stripUrlQuery((document.referrer || '').toString());
25    } catch (e) {}
26
27    // Session-entry referrer (fallback). Captured at session start the first
28    // time the visitor lands from an EXTERNAL site, mirrored to a session
29    // cookie so PHP can read it for orphan events (async/cron) that arrive
30    // without a per-page payload. Never the primary source.
31    var PYS_SESSION_ENTRY_REFERRER_KEY = 'pys_session_entry_referrer';
32    function stripUrlQuery(url) {
33        if (!url) return '';
34        var clean = String(url);
35        var q = clean.indexOf('?');
36        if (q !== -1) clean = clean.substring(0, q);
37        var h = clean.indexOf('#');
38        if (h !== -1) clean = clean.substring(0, h);
39        return clean;
40    }
41    var sessionEntryReferrer = '';
42    function getOrInitSessionEntryReferrer(consentGranted) {
43        var value = '';
44        try {
45            if (typeof window.sessionStorage !== 'undefined') {
46                value = window.sessionStorage.getItem(PYS_SESSION_ENTRY_REFERRER_KEY) || '';
47            }
48        } catch (e) {}
49
50        if (!value) {
51            var cookieValue = Cookies.get(PYS_SESSION_ENTRY_REFERRER_KEY);
52            if (cookieValue && cookieValue !== 'undefined') {
53                value = cookieValue;
54                try {
55                    if (typeof window.sessionStorage !== 'undefined') {
56                        window.sessionStorage.setItem(PYS_SESSION_ENTRY_REFERRER_KEY, value);
57                    }
58                } catch (e) {}
59            }
60        }
61
62        if (!value) {
63            var raw = '';
64            try {
65                raw = stripUrlQuery((document.referrer || '').toString());
66            } catch (e) {}
67            if (raw) {
68                var refHost = '';
69                try {
70                    refHost = new URL(raw).hostname;
71                } catch (e) {}
72                if (refHost && refHost !== window.location.hostname) {
73                    value = raw;
74                    try {
75                        if (typeof window.sessionStorage !== 'undefined') {
76                            window.sessionStorage.setItem(PYS_SESSION_ENTRY_REFERRER_KEY, value);
77                        }
78                    } catch (e) {}
79                }
80            }
81        }
82
83        // Mirror to a session cookie only once consent is given. The cookie
84        // is session-scoped (no expires) and dies with the browser, just
85        // like the sessionStorage entry.
86        if (value && consentGranted && options && options.cookie
87            && !options.cookie.disabled_all_cookie) {
88            var existingCookie = Cookies.get(PYS_SESSION_ENTRY_REFERRER_KEY);
89            if (!existingCookie || existingCookie === 'undefined') {
90                Cookies.set(PYS_SESSION_ENTRY_REFERRER_KEY, value, { path: '/', domain: domain });
91            }
92        }
93
94        sessionEntryReferrer = value;
95        return value;
96    }
97
98    // Populate sessionStorage / sessionEntryReferrer immediately. Cookie
99    // mirroring is deferred to the consent-gated path in Facebook.loadPixel().
100    getOrInitSessionEntryReferrer(false);
101
102    // Per-page event referrer (session cookie). Snapshot of document.referrer
103    // for the CURRENT page, refreshed on every page load. Read server-side
104    // by saveFbTagsInOrder() to capture the buyer's checkout-page referrer
105    // for orphan CAPI events (APT, gateway webhooks, manual status changes).
106    // Internal URLs are intentionally NOT filtered — the goal is the page
107    // that led the buyer to checkout, which is usually internal.
108    // If document.referrer is empty (direct navigation), the previous value
109    // is preserved so a session that began with an external referrer keeps
110    // it across same-tab navigations.
111    var PYS_EVENT_REFERRER_KEY = 'pys_event_referrer';
112    function writeEventReferrerCookie() {
113        if (!pageReferrer) {
114            return;
115        }
116        if (!options || !options.cookie || options.cookie.disabled_all_cookie) {
117            return;
118        }
119        try {
120            Cookies.set(PYS_EVENT_REFERRER_KEY, pageReferrer, { path: '/', domain: domain });
121        } catch (e) {}
122    }
123    /**
124     * Resolve parameter value based on mode (static or dynamic)
125     *
126     * @param {Object|string} param - Parameter object with { value, selector } or string value
127     * @param {string} key - Parameter key name
128     * @returns {string|null} - Resolved value
129     */
130    function resolveParamValue(param, key = '') {
131        // 1️⃣ null / undefined - skip this parameter
132        if (param === null || param === undefined) {
133            return null;
134        }
135
136        // 2️⃣ Handle primitive types (string, number, boolean)
137        if (typeof param !== 'object') {
138            return param;
139        }
140
141        // 3️⃣ Handle arrays - process each element recursively
142        if (Array.isArray(param)) {
143            return param.map(item => resolveParamValue(item, key));
144        }
145
146        // 4️⃣ Check if this is a configuration object (has value/selector/dynamic/input_type)
147        const isConfigObject =
148            ('value' in param || 'selector' in param || 'dynamic' in param || 'input_type' in param) &&
149            Object.keys(param).every(k =>
150                ['value', 'selector', 'dynamic', 'input_type', 'name'].includes(k)
151            );
152
153        if (isConfigObject) {
154            // STATIC MODE: selector is empty or dynamic is false
155            const isStatic =
156                (!param.dynamic || param.dynamic === false) ||
157                (!param.selector || param.selector.trim() === '');
158
159            if (isStatic) {
160                let value = param.value ?? null;
161
162                // Apply numeric conversion if needed
163                if (param.input_type === "float" || param.input_type === "int") {
164                    value = extractNumericValue(value, param.input_type === "int");
165                }
166
167                return value;
168            }
169
170            // DYNAMIC MODE: selector is present
171            try {
172                const el = document.querySelector(param.selector);
173                if (!el) {
174                    return null;
175                }
176
177                let value =
178                    el.value ||
179                    el.innerText ||
180                    el.textContent ||
181                    el.getAttribute("content") ||
182                    el.getAttribute("data-value") ||
183                    null;
184
185                // Apply numeric conversion if needed
186                if (param.input_type === "float" || param.input_type === "int") {
187                    value = extractNumericValue(value, param.input_type === "int");
188                }
189
190                return value;
191            } catch (e) {
192                return null;
193            }
194        }
195
196        // 5️⃣ Plain object (like ecommerce data) - recursively process nested values
197        return Object.fromEntries(
198            Object.entries(param)
199                .map(([k, v]) => [k, resolveParamValue(v, k)])
200                .filter(([k, v]) => v !== null && v !== undefined)
201        );
202    }
203
204    function extractNumericValue(value, isInt = false) {
205        if (value === null || value === undefined) {
206            return null;
207        }
208        if (isInt) {
209            return parseInt(value);
210        }
211        return parseFloat(value);
212    }
213    var dummyPinterest = function () {
214
215        /**
216         * Public API
217         */
218        return {
219            isEnabled: function () {},
220            disable: function () {},
221            loadPixel: function () {},
222            fireEvent: function (name, data) {
223                return false;
224            },
225            onCommentEvent: function () {},
226            onDownloadEvent: function (params) {},
227            onFormEvent: function (params) {},
228            onWooAddToCartOnButtonEvent: function (product_id) {},
229            onWooAddToCartOnSingleEvent: function (product_id, qty, is_variable, is_external, $form) {},
230            onWooRemoveFromCartEvent: function (cart_item_hash) {},
231            onEddAddToCartOnButtonEvent: function (download_id, price_index, qty) {},
232            onEddRemoveFromCartEvent: function (item) {},
233            onPageScroll: function (event) {},
234            onTime: function (event) {},
235
236        }
237
238    }();
239
240    var dummyBing = function () {
241
242        /**
243         * Public API
244         */
245        return {
246            isEnabled: function () {},
247            disable: function () {},
248            loadPixel: function () {},
249            fireEvent: function (name, data) {
250                return false;
251            },
252            onAdSenseEvent: function () {},
253            onClickEvent: function (params) {},
254            onWatchVideo: function (params) {},
255            onCommentEvent: function () {},
256            onFormEvent: function (params) {},
257            onDownloadEvent: function (params) {},
258            onWooAddToCartOnButtonEvent: function (product_id) {},
259            onWooAddToCartOnSingleEvent: function (product_id, qty, is_variable, is_external, $form) {},
260            onWooRemoveFromCartEvent: function (cart_item_hash) {},
261            onWooAffiliateEvent: function (product_id) {},
262            onWooPayPalEvent: function () {},
263            onEddAddToCartOnButtonEvent: function (download_id, price_index, qty) {},
264            onEddRemoveFromCartEvent: function (item) {},
265            onPageScroll: function (event) {},
266            onTime: function (event) {},
267        }
268
269    }();
270
271	var dummyReddit = function () {
272		/**
273		 * Public API
274		 */
275		return {
276			tag: function () {
277				return "reddit";
278			},
279			isEnabled: function () {},
280			disable: function () {},
281			loadPixel: function () {},
282			fireEvent: function ( name, data ) {
283				return false;
284			},
285			onAdSenseEvent: function ( event ) {},
286			onClickEvent: function ( params ) {},
287			onWatchVideo: function ( params ) {},
288			onCommentEvent: function ( event ) {},
289			onFormEvent: function ( params ) {},
290			onDownloadEvent: function ( params ) {},
291			onWooAddToCartOnButtonEvent: function ( product_id ) {},
292			onWooAddToCartOnSingleEvent: function ( product_id, qty, product_type, is_external, $form ) {},
293			onWooRemoveFromCartEvent: function ( cart_item_hash ) {},
294			onWooAffiliateEvent: function ( product_id ) {},
295			onWooPayPalEvent: function ( event ) {},
296			onEddAddToCartOnButtonEvent: function ( download_id, price_index, qty ) {},
297			onEddRemoveFromCartEvent: function ( item ) {},
298			onPageScroll: function ( event ) {},
299			onTime: function ( event ) {},
300		}
301	}();
302
303
304	var Utils = function (options) {
305
306        var Pinterest = dummyPinterest;
307
308        var Bing = dummyBing;
309
310		var Reddit = dummyReddit;
311
312        var gtag_loaded = false;
313
314        var gtm_loaded = false;
315
316        let isNewSession = checkSession();
317
318        var utmTerms = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'];
319
320        var utmId = ['fbadid', 'gadid', 'padid', 'bingid'];
321
322        let dataLayerName = 'dataLayerPYS';
323
324        let GTMdataLayerName = 'dataLayer';
325
326        function validateEmail(email) {
327            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,}))$/;
328            return re.test(email);
329        }
330        function getDomain(url) {
331
332            url = url.replace(/(https?:\/\/)?(www.)?/i, '');
333
334            if (url.indexOf('/') !== -1) {
335                return url.split('/')[0];
336            }
337
338            return url;
339        }
340        function loadPixels() {
341
342            if (!options.gdpr.all_disabled_by_api) {
343
344                if (!options.gdpr.facebook_disabled_by_api) {
345                    Facebook.loadPixel();
346                }
347
348                if (!options.gdpr.analytics_disabled_by_api) {
349                    Analytics.loadPixel();
350                }
351
352                if (!options.gdpr.analytics_disabled_by_api) {
353                    GTM.loadPixel();
354                }
355
356                if (!options.gdpr.pinterest_disabled_by_api) {
357                    Pinterest.loadPixel();
358                }
359
360                if (!options.gdpr.bing_disabled_by_api) {
361                    Bing.loadPixel();
362                }
363
364	            if (!options.gdpr.reddit_disabled_by_api) {
365		            Reddit.loadPixel();
366	            }
367            }
368            if (options.gdpr.consent_magic_integration_enabled && typeof CS_Data !== "undefined") {
369                if (typeof CS_Data.cs_google_analytics_consent_mode !== "undefined" && CS_Data.cs_google_analytics_consent_mode == 1) {
370                    Analytics.loadPixel();
371                }
372            }
373
374        }
375
376        function checkSession() {
377            if( Cookies.get('pys_start_session') === undefined ||
378                Cookies.get('pys_session_limit') === undefined) {
379                firstVisit = true;
380                return true
381            }
382            return false
383
384        }
385
386        function getTrafficSource() {
387
388            try {
389
390                let referrer = stripUrlQuery(document.referrer.toString()),
391                    source;
392
393                let direct = referrer.length === 0;
394                let internal = direct ? false : referrer.indexOf(options.siteUrl) === 0;
395                let external = !direct && !internal;
396
397                if (external === false) {
398                    source = 'direct';
399                } else {
400                    source = referrer;
401                }
402
403                if (source !== 'direct') {
404                    // leave only domain (Issue #70)
405                    return getDomain(source);
406                } else {
407                    return source;
408                }
409
410            } catch (e) {
411                console.error(e);
412                return 'direct';
413            }
414
415        }
416
417        /**
418         * Return query variables object with where property name is query variable
419         * and property value is query variable value.
420         */
421        function getQueryVars() {
422
423            try {
424
425                var result = {},
426                    tmp = [];
427
428                window.location.search
429                    .substr(1)
430                    .split("&")
431                    .forEach(function (item) {
432
433                        tmp = item.split('=');
434
435                        if (tmp.length > 1) {
436                            result[tmp[0]] = tmp[1];
437                        }
438
439                    });
440
441                return result;
442
443            } catch (e) {
444                console.error(e);
445                return {};
446            }
447
448        }
449
450
451        function getLandingPageValue() {
452            let name = "pys_landing_page"
453            if(options.visit_data_model === "last_visit") {
454                name = "last_pys_landing_page"
455            }
456            if(Cookies.get(name) && Cookies.get(name) !== "undefined") {
457                return Cookies.get(name);
458            }
459            else if(options.hasOwnProperty("tracking_analytics") && options.tracking_analytics.TrafficLanding){
460                return options.tracking_analytics.TrafficLanding;
461            } else{
462                return "";
463            }
464        }
465        function getTrafficSourceValue() {
466            let name = "pysTrafficSource"
467            if(options.visit_data_model === "last_visit") {
468                name = "last_pysTrafficSource"
469            }
470            if(Cookies.get(name) && Cookies.get(name) !== "undefined") {
471                return Cookies.get(name);
472            } else{
473                return "";
474            }
475        }
476
477        function getUTMId(useLast = false) {
478            try {
479                let cookiePrefix = 'pys_'
480                let terms = [];
481                if (useLast) {
482                    cookiePrefix = 'last_pys_'
483                }
484                $.each(utmId, function (index, name) {
485                    if (Cookies.get(cookiePrefix + name)) {
486                        terms[name] = Cookies.get(cookiePrefix + name)
487                    }
488                    else if(options.hasOwnProperty("tracking_analytics") && options.tracking_analytics.TrafficUtmsId[name]) {
489                        terms[name] = filterEmails(options.tracking_analytics.TrafficUtmsId[name])
490                    }
491                });
492                return terms;
493            } catch (e) {
494                console.error(e);
495                return [];
496            }
497        }
498        /**
499         * Return UTM terms from request query variables or from cookies.
500         */
501        function getUTMs(useLast = false) {
502
503            try {
504                let cookiePrefix = 'pys_'
505                if(useLast) {
506                    cookiePrefix = 'last_pys_'
507                }
508                let terms = [];
509                $.each(utmTerms, function (index, name) {
510                    if (Cookies.get(cookiePrefix + name)) {
511                        let value = Cookies.get(cookiePrefix + name);
512                        terms[name] = filterEmails(value); // do not allow email in request params (Issue #70)
513                    }
514                    else if(options.hasOwnProperty("tracking_analytics") && options.tracking_analytics.TrafficUtms[name]) {
515                        terms[name] = filterEmails(options.tracking_analytics.TrafficUtms[name])
516                    }
517                });
518
519                return terms;
520
521            } catch (e) {
522                console.error(e);
523                return [];
524            }
525
526        }
527
528        function getDateTime() {
529            var dateTime = new Array();
530            var date = new Date(),
531                days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
532                months = ['January', 'February', 'March', 'April', 'May', 'June',
533                    'July', 'August', 'September', 'October', 'November', 'December'
534                ],
535                hours = ['00-01', '01-02', '02-03', '03-04', '04-05', '05-06', '06-07', '07-08',
536                    '08-09', '09-10', '10-11', '11-12', '12-13', '13-14', '14-15', '15-16', '16-17',
537                    '17-18', '18-19', '19-20', '20-21', '21-22', '22-23', '23-24'
538                ];
539            dateTime.push(hours[date.getHours()]);
540            dateTime.push(days[date.getDay()]);
541            dateTime.push(months[date.getMonth()]);
542            return dateTime;
543        }
544
545        function filterEmails(value) {
546            return validateEmail(value) ? undefined : value;
547        }
548
549        /**
550         * PUBLIC API
551         */
552        return {
553            PRODUCT_SIMPLE : 0,
554            PRODUCT_VARIABLE : 1,
555            PRODUCT_BUNDLE : 2,
556            PRODUCT_GROUPED : 3,
557            utmTerms : utmTerms,
558            utmId : utmId,
559            fireEventForAllPixel:function(functionName,events){
560                if (events.hasOwnProperty(Facebook.tag()))
561                    Facebook[functionName](events[Facebook.tag()]);
562                if (events.hasOwnProperty(Analytics.tag()))
563                    Analytics[functionName](events[Analytics.tag()]);
564                if (events.hasOwnProperty(Pinterest.tag()))
565                    Pinterest[functionName](events[Pinterest.tag()]);
566                if (events.hasOwnProperty(Bing.tag()))
567                    Bing[functionName](events[Bing.tag()]);
568	            if (events.hasOwnProperty(Reddit.tag()))
569		            Reddit[functionName](events[Reddit.tag()]);
570
571                if (events.hasOwnProperty(GTM.tag()))
572                    GTM[functionName](events[GTM.tag()]);
573            },
574
575            setupPinterestObject: function () {
576                Pinterest = window.pys.Pinterest || Pinterest;
577                return Pinterest;
578            },
579
580            setupBingObject: function () {
581                Bing = window.pys.Bing || Bing;
582                return Bing;
583            },
584
585	        setupRedditObject: function () {
586		        Reddit = window.pys.Reddit || Reddit;
587		        return Reddit;
588	        },
589
590            // Clone all object members to another and return it
591            copyProperties: function (from, to) {
592                for (var key in from) {
593                    if("function" == typeof from[key]) {
594                        continue;
595                    }
596                    to[key] = from[key];
597                }
598                return to;
599            },
600
601            manageCookies: function () {
602
603                if (options.gdpr.cookiebot_integration_enabled && typeof Cookiebot !== 'undefined') {
604                    if (Cookiebot.consented === false && !Cookiebot.consent['marketing'] && !Cookiebot.consent['statistics']) {
605                        return;
606                    }
607                }
608                let cm_consent_not_expressed = false;
609                if ( options.gdpr.consent_magic_integration_enabled && window.CS_Data !== undefined && window.CS_Data.cs_refresh_after_consent == 1 ) {
610                    if ( Cookies.get( 'cs_viewed_cookie_policy' ) === undefined ) {
611                        cm_consent_not_expressed = true;
612                    }
613                }
614
615                if( !cm_consent_not_expressed && isNewSession && !options.cookie.disabled_all_cookie && !options.cookie.disabled_start_session_cookie) {
616                    let duration = options.last_visit_duration * 60000
617                    var now = new Date();
618                    now.setTime(now.getTime() + duration);
619                    Cookies.set('pys_session_limit', true,{ expires: now, path: '/',domain: domain })
620                    Cookies.set('pys_start_session', true,{path: '/',domain: domain});
621                }
622
623                if (options.ajaxForServerEvent && !Cookies.get('pbid') && Facebook.isEnabled()) {
624                    jQuery.ajax({
625                        url: options.ajaxUrl,
626                        dataType: 'json',
627                        data: {
628                            action: 'pys_get_pbid'
629                        },
630                        success: function (res) {
631                            if (res.data && res.data.pbid != false && options.send_external_id) {
632                                if(!(options.cookie.disabled_all_cookie || options.cookie.externalID_disabled_by_api)){
633                                    var expires = parseInt(options.external_id_expire || 180);
634                                    Cookies.set('pbid', res.data.pbid, { expires: expires, path: '/',domain: domain });
635                                }
636
637                                if(options.hasOwnProperty('facebook')) {
638                                    options.facebook.advancedMatching = {
639                                        ...options.facebook.advancedMatching,  // spread current advancedMatching values
640                                        external_id: res.data.pbid
641                                    };
642                                }
643                            }
644                        }
645                    });
646                } else if (Cookies.get('pbid') && Facebook.isEnabled()){
647                    if(Facebook.advancedMatching() && Facebook.advancedMatching().external_id && !(options.cookie.disabled_all_cookie || options.cookie.externalID_disabled_by_api)){
648                        let expires = parseInt(options.external_id_expire || 180);
649                        Cookies.set('pbid', Facebook.advancedMatching().external_id, { expires: expires, path: '/',domain: domain });
650                    }
651                }
652
653                let expires = parseInt(options.cookie_duration); //  days
654                let queryVars = getQueryVars();
655                let landing = window.location.href.split('?')[0];
656                try {
657                    // save data for first visit
658                    if(Cookies.get('pys_first_visit') === undefined && (!options.cookie.disabled_all_cookie)) {
659
660                        if(!options.cookie.disabled_first_visit_cookie)
661                        {
662                            Cookies.set('pys_first_visit', true, { expires: expires, path: '/',domain: domain });
663                        }
664                        else {
665                            Cookies.remove('pys_first_visit')
666                        }
667
668                        if(!options.cookie.disabled_trafficsource_cookie)
669                        {
670                            Cookies.set('pysTrafficSource', getTrafficSource(), { expires: expires,path: '/',domain: domain });
671                        }
672                        else {
673                            Cookies.remove('pysTrafficSource')
674                        }
675
676                        if(!options.cookie.disabled_landing_page_cookie)
677                        {
678                            Cookies.set('pys_landing_page',landing,{ expires: expires,path: '/',domain: domain });
679                        }
680                        else {
681                            Cookies.remove('pys_landing_page')
682                        }
683
684                        if(!options.cookie.disabled_utmTerms_cookie)
685                        {
686                            $.each(utmTerms, function (index, name) {
687                                if (queryVars.hasOwnProperty(name)) {
688                                    Cookies.set('pys_' + name, queryVars[name], { expires: expires,path: '/',domain: domain });
689                                } else {
690                                    Cookies.remove('pys_' + name)
691                                }
692                            });
693                        }
694                        else {
695                            $.each(utmTerms, function (index, name) {
696                                Cookies.remove('pys_' + name)
697                            });
698                        }
699
700                        if(!options.cookie.disabled_utmId_cookie)
701                        {
702                            $.each(utmId,function(index,name) {
703                                if (queryVars.hasOwnProperty(name)) {
704                                    Cookies.set('pys_' + name, queryVars[name], { expires: expires,path: '/',domain: domain });
705                                } else {
706                                    Cookies.remove('pys_' + name)
707                                }
708                            })
709                        }
710                        else {
711                            $.each(utmId, function (index, name) {
712                                Cookies.remove('pys_' + name)
713                            });
714                        }
715                    }
716
717                    // save data for last visit if it new session
718                    if(isNewSession && (!options.cookie.disabled_all_cookie)) {
719                        if(!options.cookie.disabled_trafficsource_cookie)
720                        {
721                            Cookies.set('last_pysTrafficSource', getTrafficSource(), { expires: expires,path: '/',domain: domain });
722                        }
723                        else {
724                            Cookies.remove('last_pysTrafficSource')
725                        }
726
727                        if(!options.cookie.disabled_landing_page_cookie)
728                        {
729                            Cookies.set('last_pys_landing_page',landing,{ expires: expires,path: '/',domain: domain });
730                        }
731                        else {
732                            Cookies.remove('last_pys_landing_page')
733                        }
734
735                        if(!options.cookie.disabled_utmTerms_cookie)
736                        {
737                            $.each(utmTerms, function (index, name) {
738                                if (queryVars.hasOwnProperty(name)) {
739                                    Cookies.set('last_pys_' + name, queryVars[name], { expires: expires,path: '/',domain: domain });
740                                } else {
741                                    Cookies.remove('last_pys_' + name)
742                                }
743                            });
744                        }
745                        else {
746                            $.each(utmTerms, function (index, name) {
747                                Cookies.remove('last_pys_' + name)
748                            });
749                        }
750
751                        if(!options.cookie.disabled_utmId_cookie)
752                        {
753                            $.each(utmId,function(index,name) {
754                                if (queryVars.hasOwnProperty(name)) {
755                                    Cookies.set('last_pys_' + name, queryVars[name], { expires: expires,path: '/',domain: domain });
756                                } else {
757                                    Cookies.remove('last_pys_' + name)
758                                }
759                            })
760                        }
761                        else {
762                            $.each(utmId, function (index, name) {
763                                Cookies.remove('last_pys_' + name)
764                            });
765                        }
766
767                    }
768                    if(options.cookie.disabled_start_session_cookie) {
769                        Cookies.remove('pys_start_session')
770                        Cookies.remove('pys_session_limit')
771                    }
772                    if(options.cookie.disabled_all_cookie)
773                    {
774                        Cookies.remove('pys_first_visit')
775                        Cookies.remove('pysTrafficSource')
776                        Cookies.remove('pys_landing_page')
777                        Cookies.remove('last_pys_landing_page')
778                        Cookies.remove('last_pysTrafficSource')
779                        Cookies.remove('pys_start_session')
780                        Cookies.remove('pys_session_limit')
781                        $.each(Utils.utmTerms, function (index, name) {
782                            Cookies.remove('pys_' + name)
783                        });
784                        $.each(Utils.utmId,function(index,name) {
785                            Cookies.remove('pys_' + name)
786                        })
787                        $.each(Utils.utmTerms, function (index, name) {
788                            Cookies.remove('last_pys_' + name)
789                        });
790                        $.each(Utils.utmId,function(index,name) {
791                            Cookies.remove('last_pys_' + name)
792                        });
793                    }
794                } catch (e) {
795                    console.error(e);
796                }
797            },
798            /**
799             * Generate unique ID
800             */
801            generateUniqueId : function (event) {
802                if(event.eventID.length == 0 || (event.type == "static" && options.ajaxForServerStaticEvent) || (event.type !== "static" && options.ajaxForServerEvent)) {
803                    let idKey = event.hasOwnProperty('custom_event_post_id') ? event.custom_event_post_id : event.e_id;
804                    if (!uniqueId.hasOwnProperty(idKey)) {
805                        uniqueId[idKey] = pys_generate_token();
806                    }
807                    return uniqueId[idKey];
808                }
809                else if(event.eventID.length !== 0)
810                {
811                    return event.eventID;
812                }
813            },
814
815            // Flatten object for sendBeacon compatibility
816            flattenObject: function (obj, prefix = '', res = {}) {
817                for (const [key, value] of Object.entries(obj)) {
818                    const prefixedKey = prefix
819                        ? (Array.isArray(obj) ? `${prefix}[${key}]` : `${prefix}[${key}]`)
820                        : key;
821                    if (value !== null && typeof value === 'object' && !(value instanceof File)) {
822                        this.flattenObject(value, prefixedKey, res);
823                    } else {
824                        res[prefixedKey] = value;
825                    }
826                }
827                return res;
828            },
829
830            sendServerAjaxRequest : function(url, data) {
831                if (data.action === 'pys_api_event' && data.pixel === 'facebook' && window.pysFacebookRest) {
832                    // Use Facebook REST API
833                    this.sendRestAPIRequest(data, 'facebook');
834                    return;
835                }
836
837                // Check if sendBeacon is enabled and supported
838                if (options.useSendBeacon && navigator.sendBeacon) {
839                    try {
840                        // Flatten the data object for sendBeacon compatibility
841                        const flattenedData = this.flattenObject(data);
842                        const formData = new URLSearchParams();
843
844                        // Convert flattened data to URLSearchParams
845                        for (const [key, value] of Object.entries(flattenedData)) {
846                            if (value !== null && value !== undefined) {
847                                formData.append(key, value);
848                            }
849                        }
850
851                        // Try to send using sendBeacon
852                        const success = navigator.sendBeacon(url, formData);
853                        if (success) {
854                            return; // Successfully sent via sendBeacon
855                        }
856                    } catch (e) {
857                        // If sendBeacon fails, fall back to jQuery.ajax
858                        if (options.debug) {
859                            console.log('PYS: sendBeacon failed, falling back to jQuery.ajax:', e);
860                        }
861                    }
862                }
863
864                // Fallback to jQuery.ajax
865                jQuery.ajax( {
866                    type: 'POST',
867                    url: url,
868                    data: data,
869                    headers: {
870                        'Cache-Control': 'no-cache'
871                    },
872                    success: function () {
873                    },
874                } );
875            },
876
877            sendRestAPIRequest: function (data, platform) {
878                let restApiUrl;
879
880                // Get platform-specific REST API configuration
881                switch (platform) {
882                    case 'facebook':
883                        restApiUrl = window.pysFacebookRest ? window.pysFacebookRest.restApiUrl : '/wp-json/pys-facebook/v1/event';
884                        break;
885                    default:
886                        console.error('PYS: Unknown platform for REST API:', platform);
887                        this.sendAjaxFallback(data);
888                        return;
889                }
890
891                // Prepare data for REST API
892                const restApiData = {
893                    event: data.event,
894                    data: JSON.stringify(data.data || {}),
895                    ids: JSON.stringify(data.ids || []),
896                    eventID: data.event_id || data.eventID || '',
897                    woo_order: data.woo_order || '0',
898                    edd_order: data.edd_order || '0'
899                };
900
901                const forwardedReferrer = data.referrer_url || pageReferrer;
902                if (forwardedReferrer) {
903                    restApiData.referrer_url = forwardedReferrer;
904                }
905
906                // Variant A: send the actual page URL where the event happened
907                // so the server sets event_source_url to this page, not the
908                // REST endpoint. PHP applies enable_remove_source_url_params.
909                restApiData.event_source_url = data.url || window.location.href;
910
911                // Try to send using sendBeacon first (if enabled)
912                if (options.useSendBeacon && navigator.sendBeacon) {
913                    try {
914                        const formData = new URLSearchParams();
915                        for (const [key, value] of Object.entries(restApiData)) {
916                            formData.append(key, value);
917                        }
918
919                        if (navigator.sendBeacon(restApiUrl, formData)) {
920                            return;
921                        }
922                    } catch (e) {
923                        // sendBeacon failed, continue to fetch
924                    }
925                }
926
927                // Try to send using fetch with REST API
928                if (window.fetch) {
929                    const headers = {
930                        'Content-Type': 'application/json'
931                    };
932
933                    fetch(restApiUrl, {
934                        method: 'POST',
935                        headers: headers,
936                        body: JSON.stringify(restApiData)
937                    })
938                        .then(response => {
939                            if (!response.ok) {
940                                throw new Error(platform + ' REST API request failed: ' + response.status);
941                            }
942                        })
943                        .catch(error => {
944                            // Fallback to AJAX if REST API fails
945                            if (options.debug) {
946                                console.log('PYS: ' + platform + ' REST API failed, falling back to AJAX:', error);
947                            }
948                            this.sendAjaxFallback(data);
949                        });
950                } else {
951                    // Fallback to AJAX if fetch is not supported
952                    this.sendAjaxFallback(data);
953                }
954            },
955
956
957
958            // Fallback AJAX method
959            sendAjaxFallback: function (data) {
960                jQuery.ajax({
961                    type: 'POST',
962                    url: options.ajaxUrl,
963                    data: data,
964                    headers: {
965                        'Cache-Control': 'no-cache'
966                    },
967                    success: function () {
968                    },
969                });
970            },
971            // clone object
972            clone: function(obj) {
973                var copy;
974
975                // Handle the 3 simple types, and null or undefined
976                if (null == obj || "object" != typeof obj) return obj;
977
978                // Handle Date
979                if (obj instanceof Date) {
980                    copy = new Date();
981                    copy.setTime(obj.getTime());
982                    return copy;
983                }
984
985                // Handle Array
986                if (obj instanceof Array) {
987                    copy = [];
988                    for (var i = 0, len = obj.length; i < len; i++) {
989                        if("function" == typeof obj[i]) {
990                            continue;
991                        }
992                        copy[i] = Utils.clone(obj[i]);
993                    }
994                    return copy;
995                }
996
997                // Handle Object
998                if (obj instanceof Object) {
999                    copy = {};
1000                    for (var attr in obj) {
1001                        if (obj.hasOwnProperty(attr)) {
1002                            if("function" == typeof obj[attr]) {
1003                                continue;
1004                            }
1005                            copy[attr] = Utils.clone(obj[attr]);
1006                        }
1007                    }
1008                    return copy;
1009                }
1010
1011                return obj;
1012            },
1013
1014            // Returns array of elements with given tag name
1015            getTagsAsArray: function (tag) {
1016                return [].slice.call(document.getElementsByTagName(tag));
1017            },
1018
1019            getRequestParams: function () {
1020                return [];
1021            },
1022
1023            /**
1024             * CUSTOM EVENTS
1025             */
1026
1027            setupMouseOverClickEvents: function (eventId, triggers) {
1028
1029                // Non-default binding used to avoid situations when some code in external js
1030                // stopping events propagation, eg. returns false, and our handler will never called
1031                document.addEventListener('mouseover', function(event) {
1032                    var matchedElements = Array.from(document.querySelectorAll(triggers));
1033                    var clickedElement = event.target;
1034                    var closestMatch = clickedElement.closest(triggers);
1035                    if (matchedElements.includes(clickedElement) || closestMatch){
1036                        if (event.target.classList.contains('pys-mouse-over-' + eventId)) {
1037                            return true;
1038                        } else {
1039                            event.target.classList.add('pys-mouse-over-' + eventId);
1040                        }
1041
1042                        Utils.fireTriggerEvent(eventId);
1043                    }
1044                });
1045
1046            },
1047
1048            setupCSSClickEvents: function (eventId, triggers) {
1049                // Non-default binding used to avoid situations when some code in external js
1050                // stopping events propagation, eg. returns false, and our handler will never called
1051                document.addEventListener('click', function(event) {
1052                    let matchedElements = Array.from(document.querySelectorAll(triggers)),
1053                        clickedElement = event.target,
1054                        closestMatch = clickedElement.closest(triggers);
1055
1056                    if (matchedElements.includes(clickedElement) || closestMatch){
1057                        Utils.fireTriggerEvent(eventId);
1058                    }
1059                }, true);
1060            },
1061
1062            setupURLClickEvents: function () {
1063
1064                if( !options.triggerEventTypes.hasOwnProperty('url_click') ) {
1065                    return;
1066                }
1067                // Non-default binding used to avoid situations when some code in external js
1068                // stopping events propagation, eg. returns false, and our handler will never called
1069                $('a[data-pys-event-id]').onFirst('click', function (evt) {
1070
1071                    $(this).attr('data-pys-event-id').split(',').forEach(function (eventId) {
1072
1073                        eventId = parseInt(eventId);
1074
1075                        if (isNaN(eventId) === false) {
1076                            Utils.fireTriggerEvent(eventId);
1077                        }
1078
1079                    });
1080
1081                });
1082
1083
1084            },
1085
1086            setupScrollPosEvents: function (eventId, triggers) {
1087
1088                var scrollPosThresholds = {},
1089                    docHeight = $(document).height() - $(window).height();
1090
1091                // convert % to absolute positions
1092                $.each(triggers, function (index, scrollPos) {
1093
1094                    // convert % to pixels
1095                    scrollPos = docHeight * scrollPos / 100;
1096                    scrollPos = Math.round(scrollPos);
1097
1098                    scrollPosThresholds[scrollPos] = eventId;
1099
1100                });
1101
1102                $(document).on("scroll",function () {
1103
1104                    var scrollPos = $(window).scrollTop();
1105
1106                    $.each(scrollPosThresholds, function (threshold, eventId) {
1107
1108                        // position has not reached yes
1109                        if (scrollPos <= threshold) {
1110                            return true;
1111                        }
1112
1113                        // fire event only once
1114                        if (eventId === null) {
1115                            return true;
1116                        } else {
1117                            scrollPosThresholds[threshold] = null;
1118                        }
1119
1120                        Utils.fireTriggerEvent(eventId);
1121
1122                    });
1123
1124                });
1125
1126
1127            },
1128            setupCommentEvents : function (eventId,triggers) {
1129                $('form.comment-form').on("submit",function () {
1130                    Utils.fireTriggerEvent(eventId);
1131                });
1132            },
1133
1134            /**
1135             * Events
1136             */
1137
1138            fireTriggerEvent: function (eventId) {
1139
1140                if (!options.triggerEvents.hasOwnProperty(eventId)) {
1141                    return;
1142                }
1143
1144                var event = {};
1145                var events = options.triggerEvents[eventId];
1146
1147                if (events.hasOwnProperty('facebook')) {
1148                    event = Utils.getFormFilledData(events.facebook);
1149                    Facebook.fireEvent(event.name, event);
1150                }
1151
1152                if (events.hasOwnProperty('ga')) {
1153                    event = Utils.getFormFilledData(events.ga);
1154                    Analytics.fireEvent(event.name, event);
1155                }
1156
1157                if (events.hasOwnProperty('pinterest')) {
1158                    event = Utils.getFormFilledData(events.pinterest);
1159                    Pinterest.fireEvent(event.name, event);
1160                }
1161
1162                if (events.hasOwnProperty('bing')) {
1163                    event = Utils.getFormFilledData(events.bing);
1164                    Bing.fireEvent(event.name, event);
1165                }
1166
1167	            if (events.hasOwnProperty('reddit')) {
1168                    event = Utils.getFormFilledData(events.reddit);
1169                    Reddit.fireEvent(event.name, event);
1170	            }
1171
1172                if (events.hasOwnProperty('gtm')) {
1173                    event = Utils.getFormFilledData(events.gtm);
1174                    GTM.fireEvent(event.name, event);
1175                }
1176            },
1177
1178            fireStaticEvents: function (pixel) {
1179
1180                if (options.staticEvents.hasOwnProperty(pixel)) {
1181
1182                    $.each(options.staticEvents[pixel], function (eventName, events) {
1183                        $.each(events, function (index, eventData) {
1184
1185                            eventData.fired = eventData.fired || false;
1186
1187                            if (!eventData.fired) {
1188                                eventData = Utils.getFormFilledData(eventData);
1189                                var fired = false;
1190
1191                                // fire event
1192                                if ('facebook' === pixel) {
1193                                    fired = Facebook.fireEvent(eventData.name, eventData);
1194                                } else if ('ga' === pixel) {
1195                                    fired = Analytics.fireEvent(eventData.name, eventData);
1196                                } else if ('pinterest' === pixel) {
1197                                    fired = Pinterest.fireEvent(eventData.name, eventData);
1198                                } else if ('bing' === pixel) {
1199                                    fired = Bing.fireEvent(eventData.name, eventData);
1200                                } else if ('gtm' === pixel) {
1201                                    fired = GTM.fireEvent(eventData.name, eventData);
1202                                } else if ('reddit' === pixel) {
1203	                                fired = Reddit.fireEvent(eventData.name, eventData);
1204                                }
1205
1206                                // prevent event double event firing
1207                                eventData.fired = fired;
1208
1209                            }
1210
1211                        });
1212                    });
1213
1214                }
1215
1216            },
1217
1218            /**
1219             * Load tag's JS
1220             *
1221             * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/
1222             * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/custom-dims-mets
1223             */
1224            loadGoogleTag: function (id) {
1225
1226                if (!gtag_loaded) {
1227                    let dataLayerName = this.dataLayerName;
1228                    if(options.hasOwnProperty('GATags')){
1229                        switch (options.GATags.ga_datalayer_type) {
1230                            case 'default':
1231                                dataLayerName = 'dataLayerPYS';
1232                                break;
1233                            case 'custom':
1234                                dataLayerName = options.GATags.ga_datalayer_name;
1235                                break;
1236                            default:
1237                                dataLayerName = 'dataLayer';
1238                        }
1239                    }
1240                    this.dataLayerName = dataLayerName;
1241                    (function (window, document, src) {
1242                        var a = document.createElement('script'),
1243                            m = document.getElementsByTagName('script')[0];
1244                        a.async = 1;
1245                        a.src = src;
1246                        m.parentNode.insertBefore(a, m);
1247                    })(window, document, '//www.googletagmanager.com/gtag/js?id=' + id+'&l='+this.dataLayerName);
1248
1249                    window[dataLayerName] = window[dataLayerName] || [];
1250                    window.gtag = window.gtag || function gtag() {
1251                        window[dataLayerName].push(arguments);
1252                    };
1253
1254                    if ( options.google_consent_mode ) {
1255                        let data = {};
1256                        data[ 'analytics_storage' ] = options.gdpr.analytics_storage.enabled ? options.gdpr.analytics_storage.value : 'granted';
1257                        data[ 'ad_storage' ] = options.gdpr.ad_storage.enabled ? options.gdpr.ad_storage.value : 'granted';
1258                        data[ 'ad_user_data' ] = options.gdpr.ad_user_data.enabled ? options.gdpr.ad_user_data.value : 'granted';
1259                        data[ 'ad_personalization' ] = options.gdpr.ad_personalization.enabled ? options.gdpr.ad_personalization.value : 'granted';
1260
1261                        this.loadDefaultConsent( 'consent', 'default', data );
1262                    }
1263
1264                    gtag('js', new Date());
1265                    gtag_loaded = true;
1266
1267                }
1268
1269            },
1270
1271            loadDefaultConsent: function() {
1272                window[ this.dataLayerName ].push( arguments );
1273            },
1274
1275            loadGTMScript: function (id = '') {
1276                // Strip trailing slash to allow both "domain.com" and "domain.com/" inputs.
1277                const domain = ( options.gtm.gtm_container_domain ?? 'www.googletagmanager.com' ).replace( /\/$/, '' );
1278                const loader = options.gtm.gtm_container_identifier ?? 'gtm';
1279                const gtm_auth = options.gtm.gtm_auth ?? '';
1280                const gtm_preview = options.gtm.gtm_preview ?? '';
1281                const datalayer_name = options.gtm.gtm_dataLayer_name ?? 'dataLayer';
1282
1283                window[ datalayer_name ] = window[ datalayer_name ] || [];
1284                window.gtag = window.gtag || function gtag() {
1285                    window[ datalayer_name ].push( arguments );
1286                };
1287
1288                // Push consent defaults synchronously before the GTM script tag is inserted.
1289                // When PYS loads the GTM snippet itself (non-dataLayer-only mode), this ensures
1290                // defaults are in the dataLayer before GTM processes any events.
1291                this.pushGTMConsentDefaults( datalayer_name );
1292
1293                (function(w, d, s, l, i) {
1294                    w[l] = w[l] || [];
1295                    w[l].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' });
1296                    const f = d.getElementsByTagName(s)[0];
1297                    const j = d.createElement(s);
1298                    const dl = l !== 'dataLayer' ? '&l=' + l : '';
1299                    j.async = true;
1300
1301                    // Detect domain format: bare hostname (legacy) vs full URL / relative path (new).
1302                    // Legacy "www.googletagmanager.com" → prepe
1302nd https:// and append .js.
1303                    // New format "/metrics" or "https://custom.com" → use as-is.
1304                    //   Identifier with extension (e.g. "gtm.js")  → file:   domain/gtm.js?id=
1305                    //   Identifier without extension (e.g. "g4h25o") → path: domain/g4h25o/?id=
1306                    const isNewFormat = domain.startsWith( 'http://' )
1307                                     || domain.startsWith( 'https://' )
1308                                     || domain.startsWith( '/' );
1309
1310                    if ( !isNewFormat ) {
1311                        j.src = 'https://' + domain + '/' + loader + '.js?id=' + i + dl;
1312                    } else {
1313                        const hasExtension = loader.includes( '.' );
1314                        j.src = domain + '/' + loader + ( hasExtension ? '?' : '/?' ) + 'id=' + i + dl;
1315                    }
1316
1317                    if (gtm_auth && gtm_preview) {
1318                        j.src += '&gtm_auth=' + gtm_auth + '&gtm_preview=' + gtm_preview + '&gtm_cookies_win=x';
1319                    }
1320                    f.parentNode.insertBefore(j, f);
1321                })(window, document, 'script', datalayer_name, id);
1322
1323            },
1324
1325            loadDefaultGTMConsent: function() {
1326                window[ this.GTMdataLayerName ].push( arguments );
1327            },
1328
1329            // Extracted helper: push GTM consent defaults to the dataLayer.
1330            // Called from loadGTMScript (when PYS loads the snippet) and from
1331            // GTM.loadPixel when gtm_just_data_layer is enabled, so defaults are
1332            // always present regardless of which code path loads the GTM container.
1333            pushGTMConsentDefaults: function( datalayer_name ) {
1334                if ( !options.google_consent_mode ) {
1335                    return;
1336                }
1337                let data = {};
1338                data[ 'analytics_storage' ]  = options.gdpr.analytics_storage.enabled  ? options.gdpr.analytics_storage.value  : 'granted';
1339                data[ 'ad_storage' ]         = options.gdpr.ad_storage.enabled         ? options.gdpr.ad_storage.value         : 'granted';
1340                data[ 'ad_user_data' ]       = options.gdpr.ad_user_data.enabled       ? options.gdpr.ad_user_data.value       : 'granted';
1341                data[ 'ad_personalization' ] = options.gdpr.ad_personalization.enabled ? options.gdpr.ad_personalization.value : 'granted';
1342                this.GTMdataLayerName = datalayer_name;
1343                this.loadDefaultGTMConsent( 'consent', 'default', data );
1344            },
1345
1346            /**
1347             * GDPR
1348             */
1349
1350            loadPixels: function () {
1351
1352                if (options.gdpr.ajax_enabled && !options.gdpr.consent_magic_integration_enabled) {
1353
1354                    // retrieves actual PYS GDPR filters values which allow to avoid cache issues
1355                    $.get({
1356                        url: options.ajaxUrl,
1357                        dataType: 'json',
1358                        data: {
1359                            action: 'pys_get_gdpr_filters_values'
1360                        },
1361                        success: function (res) {
1362
1363                            if (res.success) {
1364
1365                                options.gdpr.all_disabled_by_api = res.data.all_disabled_by_api;
1366                                options.gdpr.facebook_disabled_by_api = res.data.facebook_disabled_by_api;
1367                                options.gdpr.analytics_disabled_by_api = res.data.analytics_disabled_by_api;
1368                                options.gdpr.google_ads_disabled_by_api = res.data.google_ads_disabled_by_api;
1369                                options.gdpr.pinterest_disabled_by_api = res.data.pinterest_disabled_by_api;
1370                                options.gdpr.bing_disabled_by_api = res.data.bing_disabled_by_api;
1371	                            options.gdpr.reddit_disabled_by_api = res.data.reddit_disabled_by_api;
1372
1373                                options.cookie.externalID_disabled_by_api = res.data.externalID_disabled_by_api;
1374                                options.cookie.disabled_all_cookie = res.data.disabled_all_cookie;
1375                                options.cookie.disabled_advanced_form_data_cookie = res.data.disabled_advanced_form_data_cookie;
1376                                options.cookie.disabled_landing_page_cookie = res.data.disabled_landing_page_cookie;
1377                                options.cookie.disabled_first_visit_cookie = res.data.disabled_first_visit_cookie;
1378                                options.cookie.disabled_trafficsource_cookie = res.data.disabled_trafficsource_cookie;
1379                                options.cookie.disabled_utmTerms_cookie = res.data.disabled_utmTerms_cookie;
1380                                options.cookie.disabled_utmId_cookie = res.data.disabled_utmId_cookie;
1381                            }
1382
1383                            loadPixels();
1384
1385                        }
1386                    });
1387
1388                } else {
1389                    loadPixels();
1390                }
1391
1392            },
1393
1394            consentGiven: function (pixel) {
1395
1396                /**
1397                 * ConsentMagic
1398                 */
1399                if ( options.gdpr.consent_magic_integration_enabled && typeof CS_Data !== "undefined" ) {
1400
1401                    let test_prefix = CS_Data.test_prefix;
1402                    if (
1403                        ( ( typeof CS_Data.cs_google_consent_mode_enabled !== "undefined" && CS_Data.cs_google_consent_mode_enabled == 1 ) && ( pixel == 'analytics' || pixel == 'google_ads' ) )
1404                        || ( typeof CS_Data.cs_meta_ldu_mode !== "undefined" && CS_Data.cs_meta_ldu_mode && pixel == 'facebook' )
1405                        || ( typeof CS_Data.cs_reddit_ldu_mode !== "undefined" && CS_Data.cs_reddit_ldu_mode && pixel == 'reddit' )
1406                        || ( typeof CS_Data.cs_bing_consent_mode !== "undefined" && CS_Data.cs_bing_consent_mode.ad_storage.enabled && pixel == 'bing' )
1407                    ) {
1408                        if ( CS_Data.cs_cache_enabled == 0 || ( CS_Data.cs_cache_enabled == 1 && window.CS_Cache && window.CS_Cache.check_status ) ) {
1409                            return true;
1410                        } else {
1411                            return false;
1412                        }
1413                    }
1414
1415                    if( pixel == 'facebook' && ( CS_Data.cs_script_cat.facebook == 0 || CS_Data.cs_script_cat.facebook == CS_Data.cs_necessary_cat_id ) ) {
1416                        return true;
1417                    } else if( pixel == 'bing' && ( CS_Data.cs_script_cat.bing == 0 || CS_Data.cs_script_cat.bing == CS_Data.cs_necessary_cat_id ) ) {
1418                        return true;
1419                    } else if( pixel == 'analytics' && ( CS_Data.cs_script_cat.analytics == 0 || CS_Data.cs_script_cat.analytics == CS_Data.cs_necessary_cat_id ) ) {
1420                        return true;
1421                    } else if( pixel == 'google_ads' && ( CS_Data.cs_script_cat.gads == 0 || CS_Data.cs_script_cat.gads == CS_Data.cs_necessary_cat_id ) ) {
1422                        return true;
1423                    } else if( pixel == 'pinterest' && ( CS_Data.cs_script_cat.pinterest == 0 || CS_Data.cs_script_cat.pinterest == CS_Data.cs_necessary_cat_id ) ) {
1424                        return true;
1425                    } else if( pixel == 'tiktok' && ( CS_Data.cs_script_cat.tiktok == 0 || CS_Data.cs_script_cat.tiktok == CS_Data.cs_necessary_cat_id ) ) {
1426                        return true;
1427		            } else if( pixel == 'reddit' && ( CS_Data.cs_script_cat?.reddit == 0 || CS_Data.cs_script_cat?.reddit == CS_Data.cs_necessary_cat_id ) ) {
1428		                return true;
1429		            }
1430
1431                    let substring = "cs_enabled_cookie_term",
1432                        theCookies = document.cookie.split( ';' );
1433
1434                    for ( let i = 1; i <= theCookies.length; i++ ) {
1435                        if ( theCookies[ i - 1 ].indexOf( substring ) !== -1 ) {
1436                            let categoryCookie = theCookies[ i - 1 ].replace( 'cs_enabled_cookie_term' + test_prefix + '_', '' );
1437                            categoryCookie = Number( categoryCookie.replace( /\D+/g, "" ) );
1438                            let cs_cookie_val = Cookies.get( 'cs_enabled_cookie_term' + test_prefix + '_' + categoryCookie );
1439
1440                            if ( categoryCookie === CS_Data.cs_script_cat.facebook && pixel == 'facebook' ) {
1441                                return cs_cookie_val == 'yes';
1442                            } else if ( categoryCookie === CS_Data.cs_script_cat.bing && pixel == 'bing' ) {
1443                                return cs_cookie_val == 'yes';
1444                            } else if ( categoryCookie === CS_Data.cs_script_cat.analytics && pixel == 'analytics' ) {
1445                                return cs_cookie_val == 'yes';
1446                            } else if ( categoryCookie === CS_Data.cs_script_cat.gads && pixel == 'google_ads' ) {
1447                                return cs_cookie_val == 'yes';
1448                            } else if ( categoryCookie === CS_Data.cs_script_cat.pinterest && pixel == 'pinterest' ) {
1449                                return cs_cookie_val == 'yes';
1450                            } else if ( categoryCookie === CS_Data.cs_script_cat.tiktok && pixel == 'tiktok' ) {
1451                                return cs_cookie_val == 'yes';
1452                            } else if ( categoryCookie === CS_Data.cs_script_cat?.reddit && pixel == 'reddit' ) {
1453	                            return cs_cookie_val == 'yes';
1454                            }
1455                        }
1456                    }
1457
1458                    return false;
1459                }
1460
1461                /**
1462                 * Real Cookie Banner
1463                 */
1464                if(options.gdpr.real_cookie_banner_integration_enabled) {
1465                    var consentApi = window.consentApi;
1466                    if (consentApi) {
1467                        switch (pixel) {
1468                            case "analytics":
1469                                return consentApi.consentSync("http", "_ga", "*").cookieOptIn;
1470                            case "facebook":
1471                                return consentApi.consentSync("http", "_fbp", "*").cookieOptIn;
1472                            case "pinterest":
1473                                return consentApi.consentSync("http", "_pinterest_sess", ".pinterest.com").cookieOptIn;
1474                            default:
1475                                return true;
1476                        }
1477                    }
1478                }
1479
1480                /**
1481                 * Cookiebot
1482                 */
1483                if (options.gdpr.cookiebot_integration_enabled && typeof Cookiebot !== 'undefined') {
1484
1485                    var cookiebot_consent_category = options.gdpr['cookiebot_' + pixel + '_consent_category'];
1486
1487                    if (options.gdpr[pixel + '_prior_consent_enabled']) {
1488                        if (Cookiebot.consented === true || Cookiebot.consent[cookiebot_consent_category]) {
1489                            return true;
1490                        }
1491                    } else {
1492                        if (Cookiebot.consent[cookiebot_consent_category]) {
1493                            return true;
1494                        }
1495                    }
1496
1497                    return false;
1498
1499                }
1500
1501                /**
1502                 * Cookie Notice
1503                 */
1504                if (options.gdpr.cookie_notice_integration_enabled && typeof cnArgs !== 'undefined') {
1505
1506                    var cn_cookie = Cookies.get(cnArgs.cookieName);
1507
1508                    if (options.gdpr[pixel + '_prior_consent_enabled']) {
1509                        if (typeof cn_cookie === 'undefined' || cn_cookie === 'true') {
1510                            return true;
1511                        }
1512                    } else {
1513                        if (cn_cookie === 'true') {
1514                            return true;
1515                        }
1516                    }
1517
1518                    return false;
1519
1520                }
1521
1522                /**
1523                 * Cookie Law Info
1524                 */
1525                if (options.gdpr.cookie_law_info_integration_enabled) {
1526                    var cli_cookie = Cookies.get('cookieyes-consent') ?? Cookies.get('wt_consent') ?? Cookies.get('viewed_cookie_policy');
1527                    if (options.gdpr[pixel + '_prior_consent_enabled']) {
1528                        if (typeof cli_cookie === 'undefined') return true;
1529                        if (
1530                            cli_cookie &&
1531                            (cli_cookie === Cookies.get('cookieyes-consent') || cli_cookie === Cookies.get('wt_consent'))
1532                        ) {
1533                            if (getCookieYes('analytics') === 'yes') {
1534                                return true;
1535                            }
1536                        } else if (cli_cookie && cli_cookie === Cookies.get('viewed_cookie_policy')) {
1537                            if (Cookies.get('viewed_cookie_policy') === 'yes') {
1538                                return true;
1539                            }
1540                        }
1541                    } else {
1542                        if (
1543                            cli_cookie &&
1544                            (cli_cookie === Cookies.get('cookieyes-consent') || cli_cookie === Cookies.get('wt_consent'))
1545                        ) {
1546                            if (getCookieYes('analytics') === 'yes') {
1547                                return true;
1548                            }
1549                        } else if (cli_cookie && cli_cookie === Cookies.get('viewed_cookie_policy')) {
1550                            if (Cookies.get('viewed_cookie_policy') === 'yes') {
1551                                return true;
1552                            }
1553                        }
1554                    }
1555                    return false;
1556                }
1557
1558                return true;
1559
1560            },
1561
1562            setupGdprCallbacks: function () {
1563                /**
1564                 * ConsentMagic
1565                 */
1566                if (options.gdpr.consent_magic_integration_enabled && typeof CS_Data !== "undefined") {
1567                    let test_prefix = CS_Data.test_prefix,
1568                        cs_refresh_after_consent = false,
1569                        substring = "cs_enabled_cookie_term";
1570
1571                    if (CS_Data.cs_refresh_after_consent == 1) {
1572                        cs_refresh_after_consent = CS_Data.cs_refresh_after_consent;
1573                    }
1574
1575                    let consent_actions = function () {
1576                        let theCookies = document.cookie.split( ';' );
1577
1578                        let consent = {
1579                            facebook: true,
1580                            ga: true,
1581                            google_ads: true,
1582                            tiktok: true,
1583                            bing: true,
1584                            pinterest: true,
1585                            gtm: true,
1586	                        reddit: true,
1587                        };
1588
1589                        for (let i = 1 ; i <= theCookies.length; i++) {
1590                            if (theCookies[i-1].indexOf(substring) !== -1) {
1591                                let categoryCookie = theCookies[i-1].replace('cs_enabled_cookie_term'+test_prefix+'_','');
1592                                categoryCookie = Number(categoryCookie.replace(/\D+/g,""));
1593                                let cs_cookie_val = Cookies.get('cs_enabled_cookie_term'+test_prefix+'_'+categoryCookie);
1594                                if(cs_cookie_val == 'yes') {
1595                                    if ( ( categoryCookie === CS_Data.cs_script_cat.facebook ) || ( typeof CS_Data.cs_meta_ldu_mode !== "undefined" && CS_Data.cs_meta_ldu_mode ) ) {
1596                                        Facebook.loadPixel();
1597                                    }
1598
1599                                    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 ) ) {
1600                                        Bing.loadPixel();
1601                                    }
1602
1603                                    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)
1603) {
1604
1605                                        Analytics.loadPixel();
1606                                    }
1607
1608                                    if (categoryCookie === CS_Data.cs_script_cat.pinterest) {
1609                                        Pinterest.loadPixel();
1610                                    }
1611
1612	                                if ( ( categoryCookie === CS_Data.cs_script_cat.reddit ) || ( typeof CS_Data.cs_reddit_ldu_mode !== "undefined" && CS_Data.cs_reddit_ldu_mode ) ) {
1613		                                Reddit.loadPixel();
1614	                                }
1615                                } else {
1616                                    if ( ( categoryCookie === CS_Data.cs_script_cat.facebook ) && ( typeof CS_Data.cs_meta_ldu_mode == "undefined" || !CS_Data.cs_meta_ldu_mode ) ) {
1617                                        Facebook.disable();
1618                                        consent.facebook = false;
1619                                    }
1620
1621                                    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 ) ) {
1622                                        Bing.disable();
1623                                        consent.bing = false;
1624                                    }
1625                                    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)) {
1626                                        Analytics.disable();
1627                                        consent.ga = false;
1628                                        consent.gtm = false;
1629                                    }
1630
1631                                    if (categoryCookie === CS_Data.cs_script_cat.pinterest) {
1632                                        Pinterest.disable();
1633                                        consent.pinterest = false;
1634                                    }
1635
1636	                                if ( ( categoryCookie === CS_Data.cs_script_cat.reddit ) && ( typeof CS_Data.cs_reddit_ldu_mode == "undefined" || !CS_Data.cs_reddit_ldu_mode ) ) {
1637		                                Reddit.disable();
1638		                                consent.reddit = false;
1639	                                }
1640                                }
1641                                if (Cookies.get('cs_enabled_advanced_matching') == 'yes') {
1642                                    Facebook.loadPixel();
1643                                }
1644                            }
1645                        }
1646                        Utils.setupGDPRData( consent );
1647                    }
1648
1649                    if (!cs_refresh_after_consent) {
1650                        consent_actions();
1651
1652                        $(document).on('click','.cs_action_btn',function(e) {
1653                            e.preventDefault();
1654
1655                            let consent = {
1656                                facebook: true,
1657                                ga: true,
1658                                bing: true,
1659                                pinterest: true,
1660                                gtm: true,
1661	                            reddit: true,
1662                            };
1663
1664                            let elm = $(this),
1665                                button_action = elm.attr('data-cs_action');
1666
1667                            if(button_action === 'allow_all') {
1668                                Facebook.loadPixel();
1669                                Bing.loadPixel();
1670                                Analytics.loadPixel();
1671                                Pinterest.loadPixel();
1672	                            Reddit.loadPixel();
1673
1674                                consent.facebook = true;
1675                                consent.bing = true;
1676                                consent.ga = true;
1677                                consent.pinterest = true;
1678	                            consent.reddit = true;
1679                                consent.gtm = true;
1680
1681                                Utils.setupGDPRData( consent );
1682                            } else if ( button_action === 'disable_all' ) {
1683                                if ( typeof CS_Data.cs_meta_ldu_mode == "undefined" || CS_Data.cs_meta_ldu_mode == 0 ) {
1684                                    Facebook.disable();
1685                                    consent.facebook = false;
1686                                }
1687
1688                                if ( typeof CS_Data.cs_bing_consent_mode == "undefined" || CS_Data.cs_bing_consent_mode.ad_storage.enabled == 0 ) {
1689                                    Bing.disable();
1690                                    consent.bing = false;
1691                                }
1692
1693                                if ( CS_Data.cs_google_analytics_consent_mode == 0 || typeof CS_Data.cs_google_analytics_consent_mode == "undefined" ) {
1694                                    Analytics.disable();
1695                                    consent.ga = false;
1696                                    consent.gtm = false;
1697                                }
1698
1699	                            if ( typeof CS_Data.cs_reddit_ldu_mode == "undefined" || CS_Data.cs_reddit_ldu_mode == 0 ) {
1700		                            Reddit.disable();
1701		                            consent.reddit = false;
1702	                            }
1703
1704                                Pinterest.disable();
1705                                consent.pinterest = false;
1706                                Utils.setupGDPRData( consent );
1707                            } else if ( button_action === 'cs_confirm' ) {
1708                                consent_actions();
1709                            }
1710                        });
1711                    }
1712                }
1713                /**
1714                 * Real Cookie Banner
1715                 */
1716                if(options.gdpr.real_cookie_banner_integration_enabled) {
1717                    let consentApi = window.consentApi;
1718                    if (consentApi) {
1719                        consentApi.consent("http", "_ga", "*")
1720                            .then(Analytics.loadPixel.bind(Analytics), Analytics.disable.bind(Analytics));
1721                        consentApi.consent("http", "_fbp", "*")
1722                            .then(Facebook.loadPixel.bind(Facebook), Facebook.disable.bind(Facebook));
1723                        consentApi.consent("http", "_pinterest_sess", ".pinterest.com")
1724                            .then(Pinterest.loadPixel.bind(Pinterest), Pinterest.disable.bind(Pinterest));
1725                        consentApi.consent("http", "_uetsid", "*")
1726                            .then(Bing.loadPixel.bind(Bing), Bing.disable.bind(Bing));
1727
1728                        let consent = {
1729                            facebook: true,
1730                            ga: true,
1731                            bing: true,
1732                            pinterest: true,
1733                            gtm: true,
1734                        };
1735
1736                        if (!consentApi.consentSync("http", "_ga", "*").cookieOptIn) {
1737                            consent.ga = false;
1738                            consent.gtm = false;
1739                        }
1740                        if (!consentApi.consentSync("http", "_fbp", "*").cookieOptIn) {
1741                            consent.facebook = false;
1742                        }
1743                        if (!consentApi.consentSync("http", "_pinterest_sess", ".pinterest.com").cookieOptIn) {
1744                            consent.pinterest = false;
1745                        }
1746                        if (!consentApi.consentSync("http", "_uetsid", "*").cookieOptIn) {
1747                            consent.bing = false;
1748                        }
1749                        Utils.setupGDPRData( consent );
1750                    }
1751                }
1752                /**
1753                 * Cookiebot
1754                 */
1755                if (options.gdpr.cookiebot_integration_enabled && typeof Cookiebot !== 'undefined') {
1756
1757                    window.addEventListener("CookiebotOnConsentReady", function() {
1758
1759                        let consent = {
1760                            facebook: true,
1761                            ga: true,
1762                            bing: true,
1763                            pinterest: true,
1764                            gtm: true,
1765                        };
1766
1767                        Utils.manageCookies();
1768                        if (Cookiebot.consent.marketing) {
1769                            Facebook.loadPixel();
1770                            Bing.loadPixel();
1771                            Pinterest.loadPixel();
1772
1773                            consent.facebook = true;
1774                            consent.bing = true;
1775                            consent.pinterest = true;
1776                        }
1777                        if (Cookiebot.consent.statistics) {
1778                            Analytics.loadPixel();
1779
1780                            consent.ga = true;
1781                            consent.gtm = true;
1782                        }
1783                        if (!Cookiebot.consent.marketing) {
1784                            Facebook.disable();
1785                            Pinterest.disable();
1786                            Bing.disable();
1787
1788                            consent.facebook = false;
1789                            consent.bing = false;
1790                            consent.pinterest = false;
1791                        }
1792                        if (!Cookiebot.consent.statistics) {
1793                            Analytics.disable();
1794
1795                            consent.ga = false;
1796                            consent.gtm = false;
1797                        }
1798
1799                        Utils.setupGDPRData( consent );
1800                    });
1801
1802                }
1803
1804                /**
1805                 * Cookie Notice
1806                 */
1807                if (options.gdpr.cookie_notice_integration_enabled) {
1808
1809                    $(document).onFirst('click', '.cn-set-cookie', function () {
1810
1811                        let consent = {};
1812
1813                        if ($(this).data('cookie-set') === 'accept') {
1814                            Facebook.loadPixel();
1815                            Analytics.loadPixel();
1816                            Pinterest.loadPixel();
1817                            Bing.loadPixel();
1818
1819                            consent = {
1820                                facebook: true,
1821                                ga: true,
1822                                bing: true,
1823                                pinterest: true,
1824                                gtm: true,
1825                            };
1826                        } else {
1827                            Facebook.disable();
1828                            Analytics.disable();
1829                            Pinterest.disable();
1830                            Bing.disable();
1831
1832                            consent = {
1833                                facebook: false,
1834                                ga: false,
1835                                bing: false,
1836                                pinterest: false,
1837                                gtm: false,
1838                            };
1839                        }
1840
1841                        Utils.setupGDPRData( consent );
1842                    });
1843
1844                    $(document).onFirst('click', '.cn-revoke-cookie', function () {
1845                        Facebook.disable();
1846                        Analytics.disable();
1847                        Pinterest.disable();
1848                        Bing.disable();
1849
1850                        let consent = {
1851                            facebook: false,
1852                            ga: false,
1853                            bing: false,
1854                            pinterest: false,
1855                            gtm: false,
1856                        };
1857                        Utils.setupGDPRData( consent );
1858
1859                    });
1860
1861                }
1862
1863                /**
1864                 * Cookie Law Info
1865                 */
1866                if (options.gdpr.cookie_law_info_integration_enabled) {
1867
1868                    $(document).onFirst('click', '#wt-cli-accept-all-btn,#cookie_action_close_header, .cky-btn-accept', function () {
1869                        setTimeout(function (){
1870                            let cli_cookie = Cookies.get('cookieyes-consent') ?? Cookies.get('wt_consent') ?? Cookies.get('viewed_cookie_policy');
1871                            if (typeof cli_cookie !== 'undefined') {
1872                                if (cli_cookie === Cookies.get('cookieyes-consent') || cli_cookie === Cookies.get('wt_consent')) {
1873                                    if (getCookieYes('analytics') === 'yes') {
1874                                        Utils.manageCookies();
1875                                    }
1876                                } else if (cli_cookie === Cookies.get('viewed_cookie_policy') && cli_cookie == 'yes') {
1877                                    Utils.manageCookies();
1878                                }
1879                            }
1880                        },1000)
1881                        Facebook.loadPixel();
1882                        Analytics.loadPixel();
1883                        Pinterest.loadPixel();
1884                        Bing.loadPixel();
1885
1886                        let consent = {
1887                            facebook: true,
1888                            ga: true,
1889                            bing: true,
1890                            pinterest: true,
1891                            gtm: true,
1892                        };
1893                        Utils.setupGDPRData( consent );
1894                    });
1895
1896                    $(document).onFirst('click', '#cookie_action_close_header_reject, .cky-btn-reject', function () {
1897                        Facebook.disable();
1898                        Analytics.disable();
1899                        Pinterest.disable();
1900                        Bing.disable();
1901
1902                        let consent = {
1903                            facebook: false,
1904                            ga: false,
1905                            bing: false,
1906                            pinterest: false,
1907                            gtm: false,
1908                        };
1909                        Utils.setupGDPRData( consent );
1910                    });
1911
1912                }
1913
1914            },
1915
1916            setupGDPRData: function ( consent ) {
1917                consent = window.btoa( JSON.stringify( consent ) );
1918                Cookies.set( 'pys_consent', consent, { expires: 365, path: '/', domain: domain } );
1919            },
1920
1921            /**
1922             * DOWNLOAD DOCS
1923             */
1924
1925            getLinkExtension: function (link) {
1926
1927                // Remove anchor, query string and everything before last slash
1928                link = link.substring(0, (link.indexOf("#") === -1) ? link.length : link.indexOf("#"));
1929                link = link.substring(0, (link.indexOf("?") === -1) ? link.length : link.indexOf("?"));
1930                link = link.substring(link.lastIndexOf("/") + 1, link.length);
1931
1932                // If there's a period left in the URL, then there's a extension
1933                if (link.length > 0 && link.indexOf('.') !== -1) {
1934                    link = link.substring(link.indexOf(".") + 1); // Remove everything but what's after the first period
1935                    return link;
1936                } else {
1937                    return "";
1938                }
1939            },
1940
1941            getLinkFilename: function (link) {
1942
1943                // Remove anchor, query string and everything before last slash
1944                link = link.substring(0, (link.indexOf("#") === -1) ? link.length : link.indexOf("#"));
1945                link = link.substring(0, (link.indexOf("?") === -1) ? link.length : link.indexOf("?"));
1946                link = link.substring(link.lastIndexOf("/") + 1, link.length);
1947
1948                // If there's a period left in the URL, then there's a extension
1949                if (link.length > 0 && link.indexOf('.') !== -1) {
1950                    return link;
1951                } else {
1952                    return "";
1953                }
1954            },
1955            /**
1956             * Enrich
1957             */
1958            isCheckoutPage: function () {
1959                return $('body').hasClass('woocommerce-checkout') || document.querySelector('.woocommerce-checkout') ||
1960                    $('body').hasClass('edd-checkout');
1961            },
1962            addCheckoutFields : function() {
1963                var utm = "";
1964                var utms = getUTMs()
1965
1966                $.each(utmTerms, function (index, name) {
1967                    if(index > 0) {
1968                        utm+="|";
1969                    }
1970                    utm+=name+":"+utms[name];
1971                });
1972                var utmIdList = "";
1973                var utmsIds = getUTMId()
1974                $.each(utmId, function (index, name) {
1975                    if(index > 0) {
1976                        utmIdList+="|";
1977                    }
1978                    utmIdList+=name+":"+utmsIds[name];
1979                });
1980                var utmIdListLast = "";
1981                var utmsIdsLast = getUTMId(true)
1982                $.each(utmId, function (index, name) {
1983                    if(index > 0) {
1984                        utmIdListLast+="|";
1985                    }
1986                    utmIdListLast+=name+":"+utmsIdsLast[name];
1987                });
1988
1989
1990                var utmLast = "";
1991                var utmsLast = getUTMs(true)
1992                $.each(utmTerms, function (index, name) {
1993                    if(index > 0) {
1994                        utmLast+="|";
1995                    }
1996                    utmLast+=name+":"+utmsLast[name];
1997                });
1998
1999                var dateTime = getDateTime();
2000                var landing = getLandingPageValue();
2001                var lastLanding = getLandingPageValue();
2002                var trafic = getTrafficSourceValue();
2003                var lastTrafic = getTrafficSourceValue();
2004
2005                var $form = null;
2006                if($('body').hasClass('woocommerce-checkout')) {
2007                    $form = $("form.woocommerce-checkout");
2008                } else {
2009                    $form = $("#edd_purchase_form");
2010                }
2011                var inputs = {'pys_utm':utm,
2012                    'pys_utm_id':utmIdList,
2013                    'pys_browser_time':dateTime.join("|"),
2014                    'pys_landing':landing,
2015                    'pys_source':trafic,
2016                    'pys_order_type': $(".wcf-optin-form").length > 0 ? "wcf-optin" : "normal",
2017
2018                    'last_pys_landing':lastLanding,
2019                    'last_pys_source':lastTrafic,
2020                    'last_pys_utm':utmLast,
2021                    'last_pys_utm_id':utmIdListLast,
2022                }
2023
2024                Object.keys(inputs).forEach(function(key,index) {
2025                    $form.append("<input type='hidden' name='"+key+"' value='"+inputs[key]+"' /> ");
2026                });
2027
2028
2029            },
2030            getAdvancedFormData: function () {
2031                let dataStr = Cookies.get("pys_advanced_form_data");
2032                if(dataStr === undefined) {
2033                    return {'first_name':"",'last_name':"",'email':"",'phone':""};
2034                } else {
2035                    return JSON.parse(dataStr);
2036                }
2037            },
2038            getFormFilledData: function ( event ) {
2039                // First, resolve static/dynamic parameters
2040                if (event.params && Object.keys(event.params).length > 0) {
2041                    Object.entries(event.params).forEach(([key, value]) => {
2042                        // Resolve parameter value (static or dynamic)
2043                        const resolvedValue = resolveParamValue(value, key);
2044                        if (resolvedValue !== null) {
2045                            event.params[key] = resolvedValue;
2046                        }
2047                        else {
2048                            delete event.params[key];
2049                        }
2050                    });
2051                }
2052                return event;
2053            }
2054        };
2055
2056    }(options);
2057
2058    var Facebook = function (options) {
2059
2060
2061        var defaultEventTypes = [
2062            'PageView',
2063            'ViewContent',
2064            'Search',
2065            'AddToCart',
2066            'AddToWishlist',
2067            'InitiateCheckout',
2068            'AddPaymentInfo',
2069            'Purchase',
2070            'Lead',
2071
2072            'Subscribe',
2073            'CustomizeProduct',
2074            'FindLocation',
2075            'StartTrial',
2076            'SubmitApplication',
2077            'Schedule',
2078            'Contact',
2079            'Donate'
2080        ];
2081
2082        var initialized = false;
2083        var genereateFbp = function (){
2084            return !Cookies.get('_fbp') ? 'fb.1.'+Date.now()+'.'+Math.floor(1000000000 + Math.random() * 9000000000) : Cookies.get('_fbp');
2085        };
2086        var genereateFbc = function (){
2087            return getUrlParameter('fbclid') ? 'fb.1.'+Date.now()+'.'+getUrlParameter('fbclid') : ''
2088        };
2089        // fire server side event gdpr plugin installed
2090        var isApiDisabled = options.gdpr.all_disabled_by_api ||
2091            options.gdpr.facebook_disabled_by_api ||
2092            options.gdpr.cookiebot_integration_enabled ||
2093            options.gdpr.consent_magic_integration_enabled ||
2094            options.gdpr.cookie_notice_integration_enabled ||
2095            options.gdpr.cookie_law_info_integration_enabled;
2096
2097        /**
2098         *
2099         * @param allData
2100         * @param params
2101         * @returns {string | null}
2102         */
2103        function sendFbServerEvent(allData,name,params) {
2104            let eventId = null;
2105            if(options.facebook.serverApiEnabled) {
2106
2107                if(allData.e_id === "woo_remove_from_cart") {// server event will sended from hook
2108                    Facebook.updateEventId(allData.name);
2109                    allData.eventID = Facebook.getEventId(allData.name);
2110                } else {
2111                    // send event from server if they was bloc by gdpr or need send with delay
2112                    allData.eventID = Utils.generateUniqueId(allData);
2113
2114                    if(Cookies.get('_fbp')){
2115                        params._fbp = Cookies.get('_fbp');
2116                    }
2117                    if(Cookies.get('_fbc')){
2118                        params._fbc = Cookies.get('_fbc');
2119                    }
2120
2121                    if( options.ajaxForServerEvent || isApiDisabled ){
2122                        var json = {
2123                            action: 'pys_api_event',
2124                            pixel: 'facebook',
2125                            event: name,
2126                            data:params,
2127                            ids:options.facebook.pixelIds,
2128                            eventID:allData.eventID,
2129                            url:window.location.href,
2130                            ajax_event:options.ajax_event
2131                        };
2132                        if(allData.hasOwnProperty('woo_order')) {
2133                            json['woo_order'] = allData.woo_order;
2134                        }
2135                        if(allData.hasOwnProperty('edd_order')) {
2136                            json['edd_order'] = allData.edd_order;
2137                        }
2138                        if (pageReferrer) {
2139                            json.referrer_url = pageReferrer;
2140                        }
2141
2142                        if (allData.e_id === "automatic_event_internal_link" || allData.e_id === "automatic_event_outbound_link") {
2143                            setTimeout(() => Utils.sendServerAjaxRequest(options.ajaxUrl, json), 500);
2144                        } else if (allData.type != 'static') {
2145                            Utils.sendServerAjaxRequest(options.ajaxUrl, json);
2146                        }
2147
2148                        if ( ( allData.type == 'static' && options.ajaxForServerStaticEvent ) || ( allData.hasOwnProperty( 'ajaxFire' ) && allData.ajaxFire ) ) {
2149                            Utils.sendServerAjaxRequest( options.ajaxUrl, json );
2150                        }
2151                    }
2152                }
2153                delete params._fbp;
2154                delete params._fbc;
2155                eventId = allData.eventID
2156            }
2157            return eventId;
2158        }
2159
2160        function fireEvent(name, allData) {
2161
2162            if(typeof window.pys_event_data_filter === "function" && window.pys_disable_event_filter(name,'facebook')) {
2163                return;
2164            }
2165
2166            var actionType = defaultEventTypes.includes(name) ? 'track' : 'trackCustom';
2167            var data = allData.params;
2168            var params = {};
2169            var arg = {};
2170            Utils.copyProperties(data, params);
2171            let eventId = sendFbServerEvent(allData,name,params)
2172
2173
2174            if("hCR" === name) {
2175                return;
2176            }
2177
2178            if (options.debug) {
2179                console.log('[Facebook] ' + name, params,"eventID",eventId);
2180            }
2181
2182            if(eventId != null) {
2183                arg.eventID = eventId;
2184            }
2185
2186            fbq(actionType, name, params, arg);
2187
2188        }
2189
2190        /**
2191         * Public API
2192         */
2193        return {
2194            tag: function() {
2195                return "facebook";
2196            },
2197            isEnabled: function () {
2198                return options.hasOwnProperty('facebook');
2199            },
2200
2201            disable: function () {
2202                initialized = false;
2203            },
2204            advancedMatching: function () {
2205                if(options.facebook.advancedMatchingEnabled) {
2206                    let advancedMatchingForm = Utils.getAdvancedFormData();
2207                    let advancedMatching = {};
2208                    if(Object.keys(options.facebook.advancedMatching).length > 0) {
2209                        advancedMatching = options.facebook.advancedMatching;
2210                    }
2211
2212                    if(!advancedMatching.hasOwnProperty("em")
2213                        && advancedMatchingForm.hasOwnProperty("email") && advancedMatchingForm["email"].length > 0) {
2214                        advancedMatching["em"] = advancedMatchingForm["email"];
2215                    }
2216                    if(!advancedMatching.hasOwnProperty("ph")
2217                        && advancedMatchingForm.hasOwnProperty("phone") && advancedMatchingForm["phone"].length > 0) {
2218                        advancedMatching["ph"] = advancedMatchingForm["phone"];
2219                    }
2220                    if(!advancedMatching.hasOwnProperty("fn")
2221                        && advancedMatchingForm.hasOwnProperty("first_name") && advancedMatchingForm["first_name"].length > 0) {
2222                        advancedMatching["fn"] = advancedMatchingForm["first_name"];
2223                    }
2224                    if(!advancedMatching.hasOwnProperty("ln")
2225                        && advancedMatchingForm.hasOwnProperty("last_name") && advancedMatchingForm["last_name"].length > 0) {
2226                        advancedMatching["ln"] = advancedMatchingForm["last_name"];
2227                    }
2228                    if(!advancedMatching.hasOwnProperty("external_id")){
2229                        if (Cookies.get('pbid') || (options.hasOwnProperty('pbid') && options.pbid)) {
2230                            advancedMatching["external_id"] = Cookies.get('pbid') ? Cookies.get('pbid') : options.pbid;
2231                        }
2232                    }
2233                    else if(advancedMatching.external_id != Cookies.get('pbid'))
2234                    {
2235                        advancedMatching["external_id"] = Cookies.get('pbid') ? Cookies.get('pbid') : advancedMatching.external_id;
2236                    }
2237                    if(Object.keys(advancedMatching).length > 0) {
2238                        return advancedMatching;
2239                    }
2240                }
2241                return false
2242            },
2243            /**
2244             * Load pixel's JS
2245             */
2246            loadPixel: function () {
2247
2248                if (initialized || !this.isEnabled() || !Utils.consentGiven('facebook')) {
2249                    return;
2250                }
2251
2252                !function (f, b, e, v, n, t, s) {
2253                    if (f.fbq) return;
2254                    n = f.fbq = function () {
2255                        n.callMethod ?
2256                            n.callMethod.apply(n, arguments) : n.queue.push(arguments)
2257                    };
2258                    if (!f._fbq) f._fbq = n;
2259                    n.push = n;
2260                    n.loaded = !0;
2261                    n.version = '2.0';
2262                    n.agent = 'dvpixelyoursite';
2263                    n.queue = [];
2264                    t = b.createElement(e);
2265                    t.async = !0;
2266                    t.src = v;
2267                    s = b.getElementsByTagName(e)[0];
2268                    s.parentNode.insertBefore(t, s)
2269                }(window,
2270                    document, 'script', 'https://connect.facebook.net/en_US/fbevents.js');
2271
2272                let expires = parseInt(options.cookie_duration);
2273                if(!Cookies.get('_fbp')) {
2274                    Cookies.set('_fbp',genereateFbp(),  { expires: expires,path: '/',domain: domain });
2275                }
2276
2277                if(getUrlParameter('fbclid')) {
2278                    Cookies.set('_fbc',genereateFbc(),  { expires: expires,path: '/',domain: domain });
2279                }
2280
2281                // Now that Facebook consent is confirmed, mirror the session
2282                // entry referrer (if any) into the session cookie so PHP can
2283                // use it as a fallback for orphan server-only events.
2284                getOrInitSessionEntryReferrer(true);
2285
2286                // Refresh the per-page event referrer cookie so checkout
2287                // hooks can snapshot the buyer's prior page.
2288                writeEventReferrerCookie();
2289
2290                // initialize pixel
2291                options.facebook.pixelIds.forEach(function (pixelId) {
2292                    if (options.facebook.removeMetadata) {
2293                        fbq('set', 'autoConfig', false, pixelId);
2294                    }
2295                    let advancedMatching = Facebook.advancedMatching();
2296
2297                    if ( +options.facebook.meta_ldu === 1  ) {
2298                        fbq( 'dataProcessingOptions', [ 'LDU' ], 0, 0 );
2299                    }
2300
2301                    if (options.gdpr.consent_magic_integration_enabled && typeof CS_Data !== "undefined") {
2302                        if(!advancedMatching) {
2303                            fbq('init', pixelId);
2304                        } else {
2305                            var test_prefix = CS_Data.test_prefix;
2306                            var cs_advanced_matching = Cookies.get('cs_enabled_advanced_matching'+test_prefix);
2307                            if (jQuery('#cs_enabled_advanced_matching'+test_prefix).length > 0) {
2308                                if (cs_advanced_matching == 'yes') {
2309                                    fbq('init', pixelId, advancedMatching);
2310                                } else {
2311                                    fbq('init', pixelId);
2312                                }
2313                            } else {
2314                                fbq('init', pixelId, advancedMatching);
2315                            }
2316                        }
2317                    } else {
2318                        if(!advancedMatching) {
2319                            fbq('init', pixelId);
2320                        }  else {
2321                            fbq('init', pixelId, advancedMatching);
2322                        }
2323                    }
2324                });
2325
2326                initialized = true;
2327
2328                Utils.fireStaticEvents('facebook');
2329
2330            },
2331
2332            fireEvent: function (name, data) {
2333
2334                if (!initialized || !this.isEnabled()) {
2335                    return false;
2336                }
2337
2338                data.delay = data.delay || 0;
2339                data.params = data.params || {};
2340
2341                if (data.delay === 0) {
2342
2343                    fireEvent(name, data);
2344
2345                } else {
2346
2347                    setTimeout(function (name, params) {
2348                        fireEvent(name, params);
2349                    }, data.delay * 1000, name, data);
2350
2351                }
2352
2353                return true;
2354
2355            },
2356
2357            onCommentEvent: function (event) {
2358                this.fireEvent(event.name, event);
2359            },
2360
2361            onDownloadEvent: function (event) {
2362                this.fireEvent(event.name, event);
2363            },
2364
2365            onFormEvent: function (event) {
2366
2367                this.fireEvent(event.name, event);
2368
2369            },
2370
2371            onWooAddToCartOnButtonEvent: function (product_id) {
2372
2373                if(!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
2374                    return;
2375                var event = options.dynamicEvents.woo_add_to_cart_on_button_click[this.tag()];
2376                window.pysWooProductData = window.pysWooProductData || [];
2377                if (window.pysWooProductData.hasOwnProperty(product_id)) {
2378                    if (window.pysWooProductData[product_id].hasOwnProperty('facebook')) {
2379                        event = Utils.copyProperties(event, {})
2380                        Utils.copyProperties(window.pysWooProductData[product_id]['facebook'].params, event.params)
2381                        this.fireEvent(event.name, event);
2382                    }
2383                }
2384            },
2385
2386            onWooAddToCartOnSingleEvent: function (product_id, qty, product_type, $form) {
2387
2388                window.pysWooProductData = window.pysWooProductData || [];
2389                if(!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
2390                    return;
2391                var event = Utils.clone(options.dynamicEvents.woo_add_to_cart_on_button_click[this.tag()]);
2392
2393                if (product_type === Utils.PRODUCT_VARIABLE && !options.facebook.wooVariableAsSimple) {
2394                    product_id = parseInt($form.find('input[name="variation_id"]').val());
2395                }
2396
2397                if (window.pysWooProductData.hasOwnProperty(product_id)) {
2398                    if (window.pysWooProductData[product_id].hasOwnProperty('facebook')) {
2399
2400
2401                        Utils.copyProperties(window.pysWooProductData[product_id]['facebook'].params, event.params);
2402
2403                        var groupValue = 0;
2404                        if(product_type === Utils.PRODUCT_GROUPED ) {
2405                            $form.find(".woocommerce-grouped-product-list .qty").each(function(index){
2406                                var childId = $(this).attr('name').replaceAll("quantity[","").replaceAll("]","");
2407                                var quantity = parseInt($(this).val());
2408                                if(isNaN(quantity)) {
2409                                    quantity = 0;
2410                                }
2411                                var childItem = window.pysWooProductData[product_id]['facebook'].grouped[childId];
2412
2413                                if(quantity == 0) {
2414                                    event.params.content_ids.forEach(function(el,index,array) {
2415                                        if(el == childItem.content_id) {
2416                                            array.splice(index, 1);
2417                                        }
2418                                    });
2419                                }
2420
2421                                if(event.params.hasOwnProperty('contents')) {
2422                                    event.params.contents.forEach(function(el,index,array) {
2423                                        if(el.id == childItem.content_id) {
2424                                            if(quantity > 0){
2425                                                el.quantity = quantity;
2426                                            } else {
2427                                                array.splice(index, 1);
2428                                            }
2429                                        }
2430                                    });
2431                                }
2432
2433
2434                                groupValue += childItem.price * quantity;
2435                            });
2436                            if(groupValue == 0) return;
2436 // skip if no items selected
2437                        }
2438
2439                        // maybe customize value option
2440                        if (options.woo.addToCartOnButtonValueEnabled && options.woo.addToCartOnButtonValueOption !== 'global') {
2441
2442                            if(product_type === Utils.PRODUCT_GROUPED) {
2443                                event.params.value = groupValue;
2444                            } else if(product_type === Utils.PRODUCT_BUNDLE) {
2445                                var data = $(".bundle_form .bundle_data").data("bundle_form_data");
2446                                var items_sum = getBundlePriceOnSingleProduct(data);
2447                                event.params.value = (parseInt(data.base_price) + items_sum )* qty;
2448                            } else {
2449                                event.params.value = event.params.value * qty;
2450                            }
2451                        }
2452
2453                        // only when non Facebook for WooCommerce logic used
2454                        if (event.params.hasOwnProperty('contents') && product_type !== Utils.PRODUCT_GROUPED) {
2455                            event.params.contents[0].quantity = qty;
2456                        }
2457
2458                        this.fireEvent(event.name, event);
2459
2460                    }
2461                }
2462            },
2463
2464            onWooRemoveFromCartEvent: function (event) {
2465                this.fireEvent(event.name, event);
2466            },
2467
2468            onEddAddToCartOnButtonEvent: function (download_id, price_index, qty) {
2469
2470                if(!options.dynamicEvents.edd_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
2471                    return;
2472                var event = Utils.clone(options.dynamicEvents.edd_add_to_cart_on_button_click[this.tag()]);
2473
2474                if (window.pysEddProductData && window.pysEddProductData.hasOwnProperty(download_id)) {
2475
2476                    var index;
2477
2478                    if (price_index) {
2479                        index = download_id + '_' + price_index;
2480                    } else {
2481                        index = download_id;
2482                    }
2483
2484                    if (window.pysEddProductData[download_id].hasOwnProperty(index)) {
2485                        if (window.pysEddProductData[download_id][index].hasOwnProperty('facebook')) {
2486
2487
2488                            Utils.copyProperties(window.pysEddProductData[download_id][index]['facebook']["params"], event.params)
2489
2490                            // maybe customize value option
2491                            if (options.edd.addToCartOnButtonValueEnabled && options.edd.addToCartOnButtonValueOption !== 'global') {
2492                                event.params.value = event.params.value * qty;
2493                            }
2494
2495                            // update contents qty param
2496                            var contents = event.params.contents;
2497                            contents[0].quantity = qty;
2498                            event.params.contents = contents;
2499
2500                            this.fireEvent(event.name,event);
2501
2502                        }
2503                    }
2504
2505                }
2506
2507            },
2508
2509            onEddRemoveFromCartEvent: function (event) {
2510                this.fireEvent(event.name, event);
2511            },
2512            onPageScroll: function (event) {
2513                this.fireEvent(event.name, event);
2514            },
2515            onTime: function (event) {
2516                this.fireEvent(event.name, event);
2517            },
2518            initEventIdCookies: function (key) {
2519                var ids = {};
2520                ids[key] = pys_generate_token(36)
2521                Cookies.set('pys_fb_event_id', JSON.stringify(ids));
2522            },
2523            updateEventId:function(key) {
2524                var cooData = Cookies.get("pys_fb_event_id")
2525                if(cooData === undefined) {
2526                    this.initEventIdCookies(key);
2527                } else {
2528                    var data = JSON.parse(cooData);
2529                    data[key] = pys_generate_token(36);
2530                    Cookies.set('pys_fb_event_id', JSON.stringify(data) );
2531                }
2532            },
2533
2534            getEventId:function (key) {
2535                var data = Cookies.get("pys_fb_event_id");
2536                if(data === undefined) {
2537                    this.initEventIdCookies(key);
2538                    data = Cookies.get("pys_fb_event_id");
2539                }
2540                return JSON.parse(data)[key];
2541            },
2542
2543            sendFacebookRestAPIRequest: function(allData, name, params) {
2544                if (typeof window.pysFacebookRest === 'undefined' || !window.pysFacebookRest.restApiUrl) {
2545                    return;
2546                }
2547
2548                const restApiData = {
2549                    event: name,
2550                    data: JSON.stringify(params),
2551                    ids: allData.pixelIds || options.facebook.pixelIds,
2552                    eventID: allData.eventID,
2553                    woo_order: allData.woo_order || 0,
2554                    edd_order: allData.edd_order || 0
2555                };
2556
2557                if (pageReferrer) {
2558                    restApiData.referrer_url = pageReferrer;
2559                }
2560
2561                // Variant A: send the actual page URL where the event happened
2562                // so the server sets event_source_url to this page, not the
2563                // REST endpoint. PHP applies enable_remove_source_url_params.
2564                restApiData.event_source_url = window.location.href;
2565
2566                // Try sendBeacon first
2567                if (navigator.sendBeacon) {
2568                    const formData = new FormData();
2569                    Object.keys(restApiData).forEach(key => {
2570                        if (Array.isArray(restApiData[key])) {
2571                            restApiData[key].forEach(value => {
2572                                formData.append(key + '[]', value);
2573                            });
2574                        } else {
2575                            formData.append(key, restApiData[key]);
2576                        }
2577                    });
2578
2579                    if (navigator.sendBeacon(window.pysFacebookRest.restApiUrl, formData)) {
2580                        return;
2581                    }
2582                }
2583
2584                // Fallback to fetch
2585                fetch(window.pysFacebookRest.restApiUrl, {
2586                    method: 'POST',
2587                    headers: {
2588                        'Content-Type': 'application/x-www-form-urlencoded',
2589                    },
2590                    body: new URLSearchParams(restApiData)
2591                }).catch(() => {
2592                    // Fallback to AJAX if fetch fails
2593                    this.sendAjaxFallback(allData, name, params);
2594                });
2595            },
2596
2597            sendAjaxFallback: function(allData, name, params) {
2598                var json = {
2599                    action: 'pys_api_event',
2600                    pixel: 'facebook',
2601                    event: name,
2602                    data: params,
2603                    ids: allData.pixelIds || options.facebook.pixelIds,
2604                    eventID: allData.eventID,
2605                    url: window.location.href,
2606                    ajax_event: options.ajax_event
2607                };
2608                if (allData.hasOwnProperty('woo_order')) {
2609                    json['woo_order'] = allData.woo_order;
2610                }
2611                if (allData.hasOwnProperty('edd_order')) {
2612                    json['edd_order'] = allData.edd_order;
2613                }
2614                if (pageReferrer) {
2615                    json.referrer_url = pageReferrer;
2616                }
2617
2618                Utils.sendServerAjaxRequest(options.ajaxUrl, json);
2619            },
2620        };
2621
2622    }(options);
2623
2624    var Analytics = function (options) {
2625
2626        var initialized = false;
2627
2628        /**
2629         * Fires event
2630         *
2631         * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/sending-data
2632         * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/events
2633         * @link: https://developers.google.com/gtagjs/reference/event
2634         * @link: https://developers.google.com/gtagjs/reference/parameter
2635         *
2636         * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/custom-dims-mets
2637         *
2638         * @param name
2639         * @param data
2640         */
2641        function fireEvent(name, data) {
2642
2643            if(typeof window.pys_event_data_filter === "function" && window.pys_disable_event_filter(name,'ga')) {
2644                return;
2645            }
2646
2647            var eventParams = Utils.copyProperties(data, {});
2648            var _fireEvent = function (tracking_id,name,params) {
2649
2650                params['send_to'] = tracking_id;
2651
2652                if (options.debug) {
2653                    console.log('[Google Analytics #' + tracking_id + '] ' + name, params);
2654                }
2655
2656                gtag('event', name, params);
2657
2658            };
2659            options.ga.trackingIds.forEach(function (tracking_id) {
2660                var copyParams = Utils.copyProperties(eventParams, {}); // copy params because mapParamsTov4 can modify it
2661                var params = mapParamsTov4(tracking_id,name,copyParams)
2662                _fireEvent(tracking_id,name,params);
2663            });
2664
2665        }
2666        function mapParamsTov4(tag,name,param) {
2667            //GA4 automatically collects a number of parameters for all events
2668            delete param.landing_page;
2669            // end
2670            if(isv4(tag)) {
2671                delete param.traffic_source;
2672                delete param.event_category;
2673                delete param.event_label;
2674                delete param.ecomm_prodid;
2675                delete param.ecomm_pagetype;
2676                delete param.ecomm_totalvalue;
2677                if(name === 'search') {
2678                    param['search'] = param.search_term;
2679                    delete param.search_term;
2680                    delete param.dynx_itemid;
2681                    delete param.dynx_pagetype;
2682                    delete param.dynx_totalvalue;
2683                }
2684            }
2685            return param;
2686        }
2687
2688        function isv4(tag) {
2689            return tag.indexOf('G') === 0;
2690        }
2691
2692        /**
2693         * Public API
2694         */
2695        return {
2696            tag: function() {
2697                return "ga";
2698            },
2699            isEnabled: function () {
2700                return options.hasOwnProperty('ga');
2701            },
2702
2703            disable: function () {
2704                initialized = false;
2705            },
2706
2707            loadPixel: function () {
2708
2709                if (initialized || !this.isEnabled() || !Utils.consentGiven('analytics')) {
2710                    return;
2711                }
2712
2713                Utils.loadGoogleTag(options.ga.trackingIds[0]);
2714                var config = {};
2715                // Cross-Domain tracking
2716                if (options.ga.crossDomainEnabled) {
2717                    config.linker = {
2718                        accept_incoming: options.ga.crossDomainAcceptIncoming,
2719                        domains: options.ga.crossDomainDomains
2720                    };
2721                }
2722                var ids = options.ga.trackingIds;
2723                // configure tracking ids
2724                ids.forEach(function (trackingId,index) {
2725                    var obj = options.ga.isDebugEnabled;
2726                    var searchValue = "index_"+index;
2727                    var config_for_tag = Object.assign({}, options.config);
2728                    config_for_tag.debug_mode = false;
2729                    config_for_tag.send_page_view = !options.ga.custom_page_view_event;
2730                    for (var key in obj) {
2731                        if (obj.hasOwnProperty(key) && obj[key] === searchValue) {
2732                            config_for_tag.debug_mode = true;
2733                            break;
2734                        }
2735                    }
2736                    if(!config_for_tag.debug_mode)
2737                    {
2738                        delete config_for_tag.debug_mode;
2739                    }
2740                    if(isv4(trackingId)) {
2741                        if(options.ga.disableAdvertisingFeatures) {
2742                            config_for_tag.allow_google_signals = false
2743                        }
2744                        if(options.ga.disableAdvertisingPersonalization) {
2745                            config_for_tag.allow_ad_personalization_signals = false
2746                        }
2747                    }
2748                    if(options.ga.hasOwnProperty('additionalConfig')){
2749                        if(options.ga.additionalConfig.hasOwnProperty(trackingId) && options.ga.additionalConfig[trackingId]){
2750                            config_for_tag.first_party_collection = options.ga.additionalConfig[trackingId].first_party_collection;
2751                        }
2752
2753                    }
2754                    if(options.ga.hasOwnProperty('serverContainerUrls')){
2755                        if(options.ga.serverContainerUrls.hasOwnProperty(trackingId) && options.ga.serverContainerUrls[trackingId].enable_server_container != false){
2756                            if(options.ga.serverContainerUrls[trackingId].server_container_url != ''){
2757                                config_for_tag.server_container_url = options.ga.serverContainerUrls[trackingId].server_container_url;
2758                            }
2759                            if(options.ga.serverContainerUrls[trackingId].transport_url != ''){
2760                                config_for_tag.transport_url = options.ga.serverContainerUrls[trackingId].transport_url;
2761                            }
2762                        }
2763                    }
2764                    if (options.gdpr.cookiebot_integration_enabled && typeof Cookiebot !== 'undefined') {
2765
2766                        var cookiebot_consent_category = options.gdpr['cookiebot_analytics_consent_category'];
2767                        if (options.gdpr['analytics_prior_consent_enabled']) {
2768                            if (Cookiebot.consented === true && Cookiebot.consent[cookiebot_consent_category]) {
2769                                gtag('config', trackingId, config_for_tag);
2770                            }
2771                        } else {
2772                            if (Cookiebot.consent[cookiebot_consent_category]) {
2773                                gtag('config', trackingId, config_for_tag);
2774                            }
2775                        }
2776                    }
2777                    else
2778                    {
2779                        gtag('config', trackingId, config_for_tag);
2780                    }
2781                });
2782
2783                initialized = true;
2784
2785                Utils.fireStaticEvents('ga');
2786
2787            },
2788
2789            fireEvent: function (name, data) {
2790
2791                if (!initialized || !this.isEnabled()) {
2792                    return false;
2793                }
2794
2795                data.delay = data.delay || 0;
2796                data.params = data.params || {};
2797                data.params.eventID = Utils.generateUniqueId(data);
2798                if (data.delay === 0) {
2799
2800                    fireEvent(name, data.params);
2801
2802                } else {
2803
2804                    setTimeout(function (name, params) {
2805                        fireEvent(name, params);
2806                    }, data.delay * 1000, name, data.params);
2807
2808                }
2809
2810                return true;
2811
2812            },
2813
2814            onCommentEvent: function (event) {
2815                this.fireEvent(event.name, event);
2816            },
2817
2818            onDownloadEvent: function (event) {
2819                this.fireEvent(event.name, event);
2820            },
2821
2822            onFormEvent: function (event) {
2823                this.fireEvent(event.name, event);
2824            },
2825
2826            onWooAddToCartOnButtonEvent: function (product_id) {
2827
2828                if(!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
2829                    return;
2830                var event = Utils.clone(options.dynamicEvents.woo_add_to_cart_on_button_click[this.tag()]);
2831
2832                if (window.pysWooProductData.hasOwnProperty(product_id)) {
2833                    if (window.pysWooProductData[product_id].hasOwnProperty('ga')) {
2834                        Utils.copyProperties(window.pysWooProductData[product_id]['ga'].params, event.params)
2835                        this.fireEvent(event.name, event);
2836                    }
2837                }
2838
2839
2840            },
2841
2842            onWooAddToCartOnSingleEvent: function (product_id, qty, product_type, $form) {
2843
2844                window.pysWooProductData = window.pysWooProductData || [];
2845
2846                if(!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
2847                    return;
2848                var event = Utils.clone(options.dynamicEvents.woo_add_to_cart_on_button_click[this.tag()]);
2849
2850                if (product_type === Utils.PRODUCT_VARIABLE && !options.ga.wooVariableAsSimple) {
2851                    product_id = parseInt($form.find('input[name="variation_id"]').val());
2852                }
2853
2854                if (window.pysWooProductData.hasOwnProperty(product_id)) {
2855                    if (window.pysWooProductData[product_id].hasOwnProperty('ga')) {
2856
2857                        Utils.copyProperties(window.pysWooProductData[product_id]['ga'].params, event.params);
2858                        if(product_type === Utils.PRODUCT_GROUPED ) {
2859                            var groupValue = 0;
2860                            $form.find(".woocommerce-grouped-product-list .qty").each(function(index){
2861                                var childId = $(this).attr('name').replaceAll("quantity[","").replaceAll("]","");
2862                                var quantity = parseInt($(this).val());
2863                                if(isNaN(quantity)) {
2864                                    quantity = 0;
2865                                }
2866                                var childItem = window.pysWooProductData[product_id]['ga'].grouped[childId];
2867                                // update quantity
2868                                event.params.items.forEach(function(el,index,array) {
2869                                    if(el.id == childItem.content_id) {
2870                                        if(quantity > 0){
2871                                            el.quantity = quantity;
2872                                        } else {
2873                                            array.splice(index, 1);
2874                                        }
2875                                    }
2876                                });
2877                                groupValue += childItem.price * quantity;
2878                            });
2879                            if(options.woo.addToCartOnButtonValueEnabled &&
2880                                options.woo.addToCartOnButtonValueOption !== 'global' &&
2881                                event.params.hasOwnProperty('ecomm_totalvalue')) {
2882                                event.params.ecomm_totalvalue = groupValue;
2883                            }
2884
2885                            if(groupValue == 0) return; // skip if no items selected
2886                        } else {
2887                            // update items qty param
2888                            event.params.items[0].quantity = qty;
2889                        }
2890
2891                        // maybe customize value option
2892                        if (options.woo.addToCartOnButtonValueEnabled &&
2893                            options.woo.addToCartOnButtonValueOption !== 'global' &&
2894                            product_type !== Utils.PRODUCT_GROUPED)
2895                        {
2896                            if(event.params.hasOwnProperty('ecomm_totalvalue')) {
2897                                event.params.ecomm_totalvalue = event.params.items[0].price * qty;
2898                            }
2899
2900                        }
2901
2902
2903                        this.fireEvent(event.name, event);
2904                    }
2905                }
2906
2907            },
2908
2909            onWooRemoveFromCartEvent: function (event) {
2910
2911                this.fireEvent(event.name, event);
2912
2913            },
2914
2915            onEddAddToCartOnButtonEvent: function (download_id, price_index, qty) {
2916
2917                if(!options.dynamicEvents.edd_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
2918                    return;
2919                var event = Utils.clone(options.dynamicEvents.edd_add_to_cart_on_button_click[this.tag()]);
2920
2921
2922                if (window.pysEddProductData && window.pysEddProductData.hasOwnProperty(download_id)) {
2923
2924                    var index;
2925
2926                    if (price_index) {
2927                        index = download_id + '_' + price_index;
2928                    } else {
2929                        index = download_id;
2930                    }
2931
2932                    if (window.pysEddProductData[download_id].hasOwnProperty(index)) {
2933                        if (window.pysEddProductData[download_id][index].hasOwnProperty('ga')) {
2934
2935                            Utils.copyProperties(window.pysEddProductData[download_id][index]['ga'].params, event.params);
2936
2937                            // update items qty param
2938                            event.params.items[0].quantity = qty;
2939
2940                            this.fireEvent(event.name,event);
2941
2942                        }
2943                    }
2944
2945                }
2946
2947            },
2948
2949            onEddRemoveFromCartEvent: function (event) {
2950                this.fireEvent(event.name, event);
2951            },
2952            onPageScroll: function (event) {
2953                this.fireEvent(event.name, event);
2954            },
2955            onTime: function (event) {
2956                this.fireEvent(event.name, event);
2957            },
2958
2959        };
2960
2961    }(options);
2962
2963    var GTM = function (options) {
2964        var initialized = false;
2965
2966        var datalayer_name = 'dataLayer';
2967        /*
2968         * @param name
2969         * @param data
2970         */
2971        function fireEvent(name, event) {
2972            if(typeof window.pys_event_data_filter === "function" && window.pys_disable_event_filter(name,'gtm')) {
2973                return;
2974            }
2975
2976
2977            var eventParams = event.params;
2978            var data = event.params;
2979            var valuesArray = Object.values(event.trackingIds);
2980            var ids = valuesArray;
2981            Utils.copyProperties(Utils.getRequestParams(), eventParams);
2982            var _fireEvent = function (tracking_id,name,params, event=null) {
2983                var eventData = {};
2984                var ContainerCodeHasTag = !options.gtm.gtm_just_data_layer && tracking_id.length > 0;
2985                if(ContainerCodeHasTag) {
2986                    params['send_to'] = tracking_id;
2987                }
2988                else if(!options.gtm.gtm_just_data_layer){
2989                    return
2990                }
2991
2992                if (params.hasOwnProperty('ecommerce')) {
2993                    eventData.ecommerce = params.ecommerce;
2994                    delete params.ecommerce;
2995                }
2996
2997                var automatedParams = { ...params };
2998                [params['manualName'], 'manualName', 'triggerType'].forEach(key => delete automatedParams[key]);
2999                if(event && (!event.hasOwnProperty('hasAutoParam') || (event.hasOwnProperty('hasAutoParam') && event.hasAutoParam))) {
3000                    eventData.automatedParameters = automatedParams;
3001                }
3002
3003// Move custom parameters to eventData
3004
3005                if (params.hasOwnProperty(params['manualName'])) {
3006                    eventData[params['manualName']] = params[params['manualName']];
3007                    delete params[params['manualName']];
3008                }
3009
3010                ['manualName','triggerType'].forEach(key => {
3011                    if (params.hasOwnProperty(key)) {
3012                        eventData[key] = params[key];
3013                        delete params[key];
3014                    }
3015                });
3016
3017                eventData.manualDataLayer = options.gtm.gtm_dataLayer_name ?? 'dataLayer';
3018
3019                eventData.event = name;
3020
3021                if (options.debug) {
3022                    if (ContainerCodeHasTag){
3023                        console.log('[Google GTM #' + tracking_id + '] ' + name, eventData);
3024                    }
3025                    else {
3026                        console.log('[Google GTM push to "'+datalayer_name+'"] ' + name, eventData);
3027                    }
3028                }
3029                window[datalayer_name].push(eventData);
3030
3031            };
3032
3033            var copyParams = Utils.copyProperties(eventParams, {}); // copy params because mapParamsToGTM can modify it
3034
3035            var params = mapParamsToGTM(ids,name,copyParams)
3036
3037            params.event_id = Utils.generateUniqueId(event);
3038
3039            _fireEvent(ids, name, params, event);
3040        }
3041
3042        function normalizeEventName(eventName) {
3043
3044            var matches = {
3045                ViewContent: 'view_item',
3046                AddToCart: 'add_to_cart',
3047                AddToWishList: 'add_to_wishlist',
3048                InitiateCheckout: 'begin_checkout',
3049                Purchase: 'purchase',
3050                Lead: 'generate_lead',
3051                CompleteRegistration: 'sign_up',
3052                AddPaymentInfo: 'set_checkout_option'
3053            };
3054
3055            return matches.hasOwnProperty(eventName) ? matches[eventName] : eventName;
3056
3057        }
3058
3059        function mapParamsToGTM(tag,name,param) {
3060            //GA4 automatically collects a number of parameters for all events
3061            var hasGTM = false;
3062
3063            // end
3064            if (Array.isArray(tag)) {
3065                hasGTM = tag.some(function (element) {
3066                    return isGTM(element);
3067                });
3068            } else if(isGTM(tag)) {
3069                // tag is a string and matches GTM
3070                hasGTM = true;
3071            }
3072            if(hasGTM) {
3073                delete param.event_category;
3074                delete param.event_label;
3075
3076                delete param.analytics_storage;
3077                delete param.ad_storage;
3078                delete param.ad_user_data;
3079                delete param.ad_personalization;
3080
3081                if(name === 'search') {
3082                    param['search'] = param.search_term;
3083                    delete param.search_term;
3084                    delete param.dynx_itemid;
3085                    delete param.dynx_pagetype;
3086                    delete param.dynx_totalvalue;
3087                }
3088            }
3089            return param;
3090        }
3091
3092        function isGTM(tag) {
3093            return tag.indexOf('GTM') === 0;
3094        }
3095        /**
3096         * Public API
3097         */
3098        return {
3099            tag: function() {
3100                return "gtm";
3101            },
3102            isEnabled: function () {
3103                return options.hasOwnProperty('gtm');
3104            },
3105            disable: function () {
3106                initialized = false;
3107            },
3108            updateEnhancedConversionData : function () {
3109                if (!initialized || !this.isEnabled()) {
3110                    return;
3111                }
3112                if(options.hasOwnProperty("tracking_analytics") && options.tracking_analytics.hasOwnProperty("userDataEnable") && options.tracking_analytics.userDataEnable) {
3113                    var advanced = Utils.getAdvancedFormData();
3114                    if (Object.keys(advanced).length > 0) {
3115                        window[datalayer_name].push({'user_data' : advanced});
3116                    }
3117                }
3118            },
3119            loadPixel: function () {
3120
3121                if (initialized || !this.isEnabled() || !Utils.consentGiven('analytics')) {
3122                    return;
3123                }
3124                datalayer_name = options.gtm.gtm_dataLayer_name ?? 'dataLayer';
3125
3126                for (var i = 0; i < options.gtm.trackingIds.length; i++) {
3127                    var trackingId = options.gtm.trackingIds[i];
3128                    if (!options.gtm.gtm_just_data_layer) {
3129                        console.log('[PYS] Google Tag Manager container code loaded');
3130                        Utils.loadGTMScript(trackingId);
3131                        break;
3132                    }
3133                }
3134                if(options.gtm.gtm_just_data_layer) {
3135                    console.warn && console.warn("[PYS] Google Tag Manager container code placement set to OFF !!!");
3136                    console.warn && console.warn("[PYS] Data layer codes are active but GTM container must be loaded using custom coding !!!");
3137                    // Push consent defaults even when GTM script loading is handled externally.
3138                    // Fixes the case where gtm_just_data_layer=true with tracking IDs configured,
3139                    // which previously skipped loadGTMScript() entirely and never pushed defaults.
3140                    Utils.pushGTMConsentDefaults( datalayer_name );
3141                    if(options.gtm.trackingIds.length == 0){
3142                        Utils.loadGTMScript();
3143                    }
3144                }
3145
3146                if(options.hasOwnProperty("tracking_analytics") && options.tracking_analytics.hasOwnProperty("userDataEnable") && options.tracking_analytics.userDataEnable){
3147                    var advanced = Utils.getAdvancedFormData();
3148                    if(Object.keys(advanced).length > 0){
3149                        window[datalayer_name].push({'user_data' : advanced});
3150                    }
3151                }
3152
3153
3154                var config = {};
3155
3156                if(options.user_id && options.user_id != 0) {
3157                    config.user_id = options.user_id;
3158                }
3159
3160                // Cross-Domain tracking
3161
3162                var ids = options.gtm.trackingIds;
3163
3164
3165                initialized = true;
3166
3167                Utils.fireStaticEvents('gtm');
3168            },
3169
3170            fireEvent: function (name, data) {
3171
3172                if (!initialized || !this.isEnabled()) {
3173                    return false;
3174                }
3175
3176                data.delay = data.delay || 0;
3177                data.params = data.params || {};
3178
3179                if (data.delay === 0) {
3180
3181                    fireEvent(name, data);
3182
3183                } else {
3184
3185                    setTimeout(function (name, params) {
3186                        fireEvent(name, params);
3187                    }, data.delay * 1000, name, data);
3188
3189                }
3190
3191                return true;
3192
3193            },
3194
3195            onCommentEvent: function (event) {
3196                this.fireEvent(event.name, event);
3197            },
3198
3199            onDownloadEvent: function (event) {
3200                this.fireEvent(event.name, event);
3201            },
3202
3203            onFormEvent: function (event) {
3204                this.fireEvent(event.name, event);
3205            },
3206
3207            onWooAddToCartOnButtonEvent: function (product_id, prod_info = null) {
3208                if(!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
3209                    return;
3210                var event = Utils.clone(options.dynamicEvents.woo_add_to_cart_on_button_click[this.tag()]);
3211
3212                if (window.pysWooProductData.hasOwnProperty(product_id)) {
3213                    if (window.pysWooProductData[product_id].hasOwnProperty('gtm')) {
3214                        Utils.copyProperties(window.pysWooProductData[product_id]['gtm'].params, event.params)
3215                        this.fireEvent(event.name, event);
3216                    }
3217                }
3218
3219            },
3220
3221            onWooAddToCartOnSingleEvent: function (product_id, qty, product_type, is_external, $form, prod_info) {
3222                window.pysWooProductData = window.pysWooProductData || [];
3223
3224                if(!options.dynamicEvents.woo_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
3225                    return;
3226                var event = Utils.clone(options.dynamicEvents.woo_add_to_cart_on_button_click[this.tag()]);
3227
3228                if (product_type === Utils.PRODUCT_VARIABLE && !options.gtm.wooVariableAsSimple) {
3229                    product_id = parseInt($form.find('input[name="variation_id"]').val());
3230                }
3231
3232                if (window.pysWooProductData.hasOwnProperty(product_id)) {
3233                    if (window.pysWooProductData[product_id].hasOwnProperty('gtm')) {
3234
3235                        Utils.copyProperties(window.pysWooProductData[product_id]['gtm'].params, event.params);
3236
3237                        params = event.params.hasOwnProperty('ecommerce') ? event.params.ecommerce : event.params;
3238
3239                        if(product_type === Utils.PRODUCT_GROUPED ) {
3240                            var groupValue = 0;
3241                            $form.find(".woocommerce-grouped-product-list .qty").each(function(index){
3242                                var childId = $(this).attr('name').replaceAll("quantity[","").replaceAll("]","");
3243                                var quantity = parseInt($(this).val());
3244                                if(isNaN(quantity)) {
3245                                    quantity = 0;
3246                                }
3247                                var childItem = window.pysWooProductData[product_id]['gtm'].grouped[childId];
3248                                params.items.forEach(function(el,index,array) {
3249                                    if(el.id == childItem.content_id) {
3250                                        if(quantity > 0){
3251                                            el.quantity = quantity;
3252                                            el.price = childItem.price;
3253                                        } else {
3254                                            array.splice(index, 1);
3255                                        }
3256                                    }
3257                                });
3258                                groupValue += childItem.price * quantity;
3259                            });
3260
3261                            if(options.woo.addToCartOnButtonValueEnabled &&
3262                                options.woo.addToCartOnButtonValueOption !== 'global' &&
3263                                params.hasOwnProperty('value')) {
3264                                params.value = groupValue;
3265                            }
3266
3267                            if(groupValue == 0) return; // skip if no items selected
3268                        } else {
3269                            // update items qty param
3270                            params.items[0].quantity = qty;
3271                        }
3272
3273                        // maybe customize value option
3274                        if (options.woo.addToCartOnButtonValueEnabled &&
3275                            options.woo.addToCartOnButtonValueOption !== 'global' &&
3276                            product_type !== Utils.PRODUCT_GROUPED)
3277                        {
3278                            if(params.hasOwnProperty('value')) {
3279                                params.value = params.items[0].price * qty;
3280                            }
3281
3282                        }
3283
3284
3285                        this.fireEvent(event.name, event);
3286                    }
3287                }
3288
3289            },
3290
3291            onWooRemoveFromCartEvent: function (event) {
3292
3293                this.fireEvent(event.name, event);
3294
3295            },
3296
3297            onEddAddToCartOnButtonEvent: function (download_id, price_index, qty) {
3298                if(!options.dynamicEvents.edd_add_to_cart_on_button_click.hasOwnProperty(this.tag()))
3299                    return;
3300                var event = Utils.clone(options.dynamicEvents.edd_add_to_cart_on_button_click[this.tag()]);
3301
3302
3303                if (window.pysEddProductData && window.pysEddProductData.hasOwnProperty(download_id)) {
3304
3305                    var index;
3306
3307                    if (price_index) {
3308                        index = download_id + '_' + price_index;
3309                    } else {
3310                        index = download_id;
3311                    }
3312
3313                    if (window.pysEddProductData[download_id].hasOwnProperty(index)) {
3314                        if (window.pysEddProductData[download_id][index].hasOwnProperty('gtm')) {
3315
3316                            Utils.copyProperties(window.pysEddProductData[download_id][index]['gtm'].params, event.params);
3317                            item = event.params.hasOwnProperty('ecommerce') ? event.params.ecommerce.items[0] : event.params.items[0];
3318                            // update items qty param
3319                            item.quantity = qty;
3320
3321                            this.fireEvent(event.name,event);
3322
3323                        }
3324                    }
3325
3326                }
3327
3328            },
3329
3330            onEddRemoveFromCartEvent: function (event) {
3331                this.fireEvent(event.name, event);
3332            },
3333            onPageScroll: function (event) {
3334                this.fireEvent(event.name, event);
3335            },
3336            onTime: function (event) {
3337                this.fireEvent(event.name, event);
3338            },
3339        };
3340
3341    }(options);
3342
3343    var getPixelBySlag = function getPixelBySlag(slug) {
3344        switch (slug) {
3345            case "facebook": return window.pys.Facebook;
3346            case "ga": return window.pys.Analytics;
3347            case "gtm": return window.pys.GTM;
3348            case "bing": return window.pys.Bing;
3349            case "pinterest": return window.pys.Pinterest;
3350	        case "reddit": return window.pys.Reddit;
3351        }
3352    }
3353
3354    window.pys = window.pys || {};
3355    window.pys.Facebook = Facebook;
3356    window.pys.Analytics = Analytics;
3357    window.pys.GTM = GTM;
3358    window.pys.Utils = Utils;
3359    window.pys.getPixelBySlag = getPixelBySlag;
3360
3361    // Allow external scripts (e.g. generatePixelCode fragments) to refresh
3362    // the uniqueId cache for a given event key, so that each new add_to_cart
3363    // action gets a fresh shared ID across all pixels.
3364    window.pys.setEventUniqueId = function(idKey, newId) {
3365        uniqueId[idKey] = newId;
3366    };
3367
3368    // Export getPixelBySlag globally for backward compatibility
3369    window.getPixelBySlag = getPixelBySlag;
3370
3371
3372    $(document).ready(function () {
3373
3374        if($("#pys_late_event").length > 0) {
3375            var dirAttr = $("#pys_late_event").attr("dir");
3376            if (dirAttr) {
3377                try {
3378                    var events = JSON.parse(dirAttr);
3379                } catch (e) {
3380                    console.warn("Invalid JSON in pys_late_event dir attribute:", e);
3381                }
3382            } else {
3383                console.warn("pys_late_event dir attribute is undefined or empty");
3384            }
3385            if (events) {
3386                for (var key in events) {
3387                    var event = {};
3388                    event[events[key].e_id] = [events[key]];
3389                    if (options.staticEvents.hasOwnProperty(key)) {
3390                        Object.assign(options.staticEvents[key], event);
3391                    } else {
3392                        options.staticEvents[key] = event;
3393                    }
3394                }
3395            }
3396        }
3397
3398        var Pinterest = Utils.setupPinterestObject();
3399        var Bing = Utils.setupBingObject();
3400	    var Reddit = Utils.setupRedditObject();
3401
3402        if(options.hasOwnProperty('cookie'))
3403        {
3404            if(options.cookie.externalID_disabled_by_api || options.cookie.disabled_all_cookie)
3405            {
3406                Cookies.remove('pbid')
3407            }
3408            if(options.cookie.disabled_advanced_form_data_cookie || options.cookie.disabled_all_cookie)
3409            {
3410                Cookies.remove('pys_advanced_form_data')
3411            }
3412            if(options.cookie.disabled_landing_page_cookie || options.cookie.disabled_all_cookie)
3413            {
3414                Cookies.remove('pys_landing_page')
3415                Cookies.remove('last_pys_landing_page')
3416            }
3417            if(options.cookie.disabled_trafficsource_cookie || options.cookie.disabled_all_cookie)
3418            {
3419                Cookies.remove('pysTrafficSource')
3420                Cookies.remove('last_pysTrafficSource')
3421            }
3422            if(options.cookie.disabled_first_visit_cookie || options.cookie.disabled_all_cookie)
3423            {
3424                Cookies.remove('pys_first_visit')
3425
3426            }
3427            if(options.cookie.disabled_utmTerms_cookie || options.cookie.disabled_all_cookie)
3428            {
3429                $.each(Utils.utmTerms, function (index, name) {
3430                    Cookies.remove('pys_' + name)
3431                });
3432                $.each(Utils.utmTerms, function (index, name) {
3433                    Cookies.remove('last_pys_' + name)
3434                });
3435            }
3436            if(options.cookie.disabled_utmId_cookie || options.cookie.disabled_all_cookie)
3437            {
3438                $.each(Utils.utmId,function(index,name) {
3439                    Cookies.remove('pys_' + name)
3440                })
3441                $.each(Utils.utmId,function(index,name) {
3442                    Cookies.remove('last_pys_' + name)
3443                });
3444            }
3445        }
3446
3447
3448        if (options.gdpr.cookie_law_info_integration_enabled) {
3449            var cli_cookie = Cookies.get('cookieyes-consent') ?? Cookies.get('viewed_cookie_policy');
3450
3451            if (typeof cli_cookie !== 'undefined') {
3452                if (cli_cookie === Cookies.get('cookieyes-consent') && getCookieYes('analytics') == 'yes') {
3453                    Utils.manageCookies();
3454                } else if (cli_cookie === Cookies.get('viewed_cookie_policy') && cli_cookie == 'yes') {
3455                    Utils.manageCookies();
3456                }
3457            }
3458        }
3459
3460        if ( options.gdpr.consent_magic_integration_enabled && typeof CS_Data !== "undefined" ) {
3461            if ( CS_Data.cs_script_cat.pys == CS_Data.cs_necessary_cat_id || CS_Data.cs_script_cat.pys == 0 ) {
3462                Utils.manageCookies();
3463            } else if ( Cookies.get( 'cs_enabled_cookie_term' + CS_Data.test_prefix + '_' + CS_Data.cs_script_cat.pys ) == 'yes' ) {
3464                Utils.manageCookies();
3465            }
3466        } else {
3467            Utils.manageCookies();
3468        }
3469
3470        Utils.setupGdprCallbacks();
3471        // page scroll event
3472        if ( options.dynamicEvents.hasOwnProperty("automatic_event_scroll")
3473        ) {
3474
3475            var singlePageScroll = function () {
3476
3477
3478                var docHeight = $(document).height() - $(window).height();
3479                var isFired = false;
3480
3481                if (options.dynamicEvents.hasOwnProperty("automatic_event_scroll")) {
3482                    var pixels = Object.keys(options.dynamicEvents.automatic_event_scroll);
3483                    for(var i = 0;i<pixels.length;i++) {
3484                        var event = Utils.clone(options.dynamicEvents.automatic_event_scroll[pixels[i]]);
3485                        var scroll = Math.round(docHeight * event.scroll_percent / 100)// convert % to absolute positions
3486
3487                        if(scroll < $(window).scrollTop()) {
3488	                        if ( pixels[i] !== 'reddit') {
3489		                        Utils.copyProperties( Utils.getRequestParams(), event.params );
3490	                        }
3491	                        getPixelBySlag( pixels[ i ] ).onPageScroll( event );
3492                            isFired = true
3493                        }
3494                    }
3495                }
3496                if(isFired) {
3497                    $(document).off("scroll",singlePageScroll);
3498                }
3499            }
3500            $(document).on("scroll",singlePageScroll);
3501        }
3502
3503
3504        if (options.dynamicEvents.hasOwnProperty("automatic_event_time_on_page")) {
3505            var pixels = Object.keys(options.dynamicEvents.automatic_event_time_on_page);
3506            var time = options.dynamicEvents.automatic_event_time_on_page[pixels[0]].time_on_page; // the same for all pixel
3507            setTimeout(function(){
3508                for(var i = 0;i<pixels.length;i++) {
3509                    var event = Utils.clone(options.dynamicEvents.automatic_event_time_on_page[pixels[i]]);
3510
3511	                if ( pixels[i] !== 'reddit') {
3512		                Utils.copyProperties(Utils.getRequestParams(), event.params);
3513	                }
3514                    getPixelBySlag(pixels[i]).onTime(event);
3515                }
3516            },time*1000);
3517        }
3518
3519        // setup Click Event
3520        if (options.dynamicEvents.hasOwnProperty("automatic_event_download")) {
3521
3522            $(document).onFirst('click', 'a, button, input[type="button"], input[type="submit"]', function (e) {
3523
3524                var $elem = $(this);
3525
3526                // Download
3527                if(options.dynamicEvents.hasOwnProperty("automatic_event_download")
3528                ) {
3529                    var isFired = false;
3530                    if ($elem.is('a')) {
3531                        var href = $elem.attr('href');
3532                        if (typeof href !== "string") {
3533                            return;
3534                        }
3535                        href = href.trim();
3536                        var extension = Utils.getLinkExtension(href);
3537                        var track_download = false;
3538
3539                        if (extension.length > 0) {
3540
3541                            if(options.dynamicEvents.hasOwnProperty("automatic_event_download") ) {
3542                                var pixels = Object.keys(options.dynamicEvents.automatic_event_download);
3543                                for (var i = 0; i < pixels.length; i++) {
3544                                    var event = Utils.clone(options.dynamicEvents.automatic_event_download[pixels[i]]);
3545                                    var extensions = event.extensions;
3546                                    if (extensions.includes(extension)) {
3547
3548                                        if( pixels[i] == "tiktok" || pixels[i] == "reddit" ) {
3549                                            getPixelBySlag(pixels[i]).fireEvent(tikEvent.name, event);
3550                                        } else {
3551                                            if (options.enable_remove_download_url_param) {
3552                                                href = stripUrlQuery(href);
3553                                            }
3554                                            event.params.download_url = href;
3555                                            event.params.download_type = extension;
3556                                            event.params.download_name = Utils.getLinkFilename(href);
3557                                            getPixelBySlag(pixels[i]).onDownloadEvent(event);
3558                                        }
3559
3560                                        isFired = true;
3561                                    }
3562                                }
3563                            }
3564                        }
3565                    }
3566                    if(isFired) { // prevent duplicate events on the same element
3567                        return;
3568                    }
3569                }
3570            });
3571        }
3572
3573
3574        // setup Dynamic events
3575        $.each(options.triggerEventTypes, function (triggerType, events) {
3576
3577            $.each(events, function (eventId, triggers) {
3578
3579                switch (triggerType) {
3580                    case 'url_click':
3581                        //@see: Utils.setupURLClickEvents()
3582                        break;
3583
3584                    case 'css_click':
3585                        Utils.setupCSSClickEvents(eventId, triggers);
3586                        break;
3587
3588                    case 'css_mouseover':
3589                        Utils.setupMouseOverClickEvents(eventId, triggers);
3590                        break;
3591
3592                    case 'scroll_pos':
3593                        Utils.setupScrollPosEvents(eventId, triggers);
3594                        break;
3595                    case 'comment':
3596                        Utils.setupCommentEvents(eventId, triggers);
3597                        break;
3598                }
3599
3600            });
3601
3602        });
3603        // setup WooCommerce events
3604        if (options.woo.enabled) {
3605
3606            // WooCommerce AddToCart
3607            if (options.dynamicEvents.hasOwnProperty("woo_add_to_cart_on_button_click")
3608                && options.woo.hasOwnProperty("addToCartCatchMethod")
3609                && options.woo.addToCartCatchMethod === "add_cart_js"
3610            ) {
3611
3612                // Loop, any kind of "simple" product, except external
3613                $('.add_to_cart_button:not(.product_type_variable,.product_type_bundle,.single_add_to_cart_button)').on("click",function (e) {
3614
3615                    var product_id = $(this).data('product_id');
3616                    if (typeof product_id !== 'undefined') {
3617                        if (options.dynamicEvents.hasOwnProperty("woo_add_to_cart_on_button_click")) {
3618                            var tmpEventID = pys_generate_token();
3619                            $.each(options.dynamicEvents.woo_add_to_cart_on_button_click, function (i, tag) {
3620                                tag.eventID = tmpEventID;
3621                                // Also refresh the uniqueId cache so server-API path
3622                                // (ajaxForServerStaticEvent) gets the same fresh ID.
3623                                var idKey = tag.hasOwnProperty('custom_event_post_id') ? tag.custom_event_post_id : tag.e_id;
3624                                uniqueId[idKey] = tmpEventID;
3625                            });
3626                        }
3627                        if (typeof product_id !== 'undefined') {
3628                            Facebook.onWooAddToCartOnButtonEvent(product_id);
3629                            Analytics.onWooAddToCartOnButtonEvent(product_id);
3630                            GTM.onWooAddToCartOnButtonEvent(product_id);
3631                            Pinterest.onWooAddToCartOnButtonEvent(product_id);
3632                            Bing.onWooAddToCartOnButtonEvent(product_id);
3633	                        Reddit.onWooAddToCartOnButtonEvent(product_id);
3634                        }
3635                    }
3636                });
3637
3638                // Single Product
3639                // tap try to https://stackoverflow.com/questions/30990967/on-tap-click-event-firing-twice-how-to-avoid-it
3640                //  $(document) not work
3641                $('body').onFirst('click','button.single_add_to_cart_button,.single_add_to_cart_button',function (e) {
3642
3643                    var $button = $(this);
3644
3645                    if ($button.hasClass('disabled')) {
3646                        return;
3647                    }
3648
3649                    var $form = $button.closest('form');
3650
3651                    var product_type = Utils.PRODUCT_SIMPLE;
3652
3653                    if ($form.length === 0) {
3654                        return ;
3655                    } else if ($form.hasClass('variations_form')) {
3656                        product_type = Utils.PRODUCT_VARIABLE;
3657                    } else if($form.hasClass('bundle_form')) {
3658                        product_type = Utils.PRODUCT_BUNDLE;
3659                    } else if($form.hasClass('grouped_form')) {
3660                        product_type = Utils.PRODUCT_GROUPED;
3661                    }
3662
3663
3664
3665
3666                    var product_id;
3667                    var qty;
3668
3669                    if (product_type === Utils.PRODUCT_GROUPED) {
3670                        qty = 1;
3671                        product_id = parseInt($form.find('*[name="add-to-cart"]').val());
3672                    } else if (product_type === Utils.PRODUCT_VARIABLE) {
3673                        product_id = parseInt($form.find('*[name="add-to-cart"]').val());
3674                        var qtyTag = $form.find('input[name="quantity"]');
3675                        if(qtyTag.length <= 0) {
3676                            qtyTag = $form.find('select[name="quantity"]');
3677                        }
3678                        qty = parseInt(qtyTag.val());
3679                    } else {
3680                        product_id = parseInt($form.find('*[name="add-to-cart"]').val());
3681                        var qtyTag = $form.find('input[name="quantity"]');
3682                        if(qtyTag.length <= 0) {
3683                            qtyTag = $form.find('select[name="quantity"]');
3684                        }
3685                        qty = parseInt(qtyTag.val());
3686                    }
3687
3688                    if(options.dynamicEvents.hasOwnProperty("woo_add_to_cart_on_button_click")){
3689                        var tmpEventID = pys_generate_token();
3690                        $.each(options.dynamicEvents.woo_add_to_cart_on_button_click, function (i, tag) {
3691                            tag.eventID = tmpEventID;
3692                            // Also refresh the uniqueId cache so server-API path
3693                            // (ajaxForServerStaticEvent) gets the same fresh ID.
3694                            var idKey = tag.hasOwnProperty('custom_event_post_id') ? tag.custom_event_post_id : tag.e_id;
3695                            uniqueId[idKey] = tmpEventID;
3696                        });
3697                    }
3698
3699                    Facebook.onWooAddToCartOnSingleEvent(product_id, qty, product_type, $form);
3700                    Analytics.onWooAddToCartOnSingleEvent(product_id, qty, product_type, $form);
3701
3702                    GTM.onWooAddToCartOnSingleEvent(product_id, qty, product_type, $form);
3703
3704                    Pinterest.onWooAddToCartOnSingleEvent(product_id, qty, product_type, false, $form);
3705                    Bing.onWooAddToCartOnSingleEvent(product_id, qty, product_type, false, $form);
3706	                Reddit.onWooAddToCartOnSingleEvent(product_id, qty, product_type, false, $form);
3707
3708                });
3709
3710            }
3711
3712            // WooCommerce RemoveFromCart
3713            if (options.dynamicEvents.hasOwnProperty("woo_remove_from_cart")) {
3714
3715                $('body').on('click', options.woo.removeFromCartSelector, function (e) {
3716
3717                    var $a = $(e.currentTarget),
3718                        href = $a.attr('href');
3719
3720                    // extract cart item hash from remove button URL
3721                    var regex = new RegExp("[\\?&]remove_item=([^&#]*)"),
3722                        results = regex.exec(href);
3723
3724                    if (results !== null) {
3725
3726                        var item_hash = results[1];
3727
3728                        if (options.dynamicEvents["woo_remove_from_cart"].hasOwnProperty(item_hash)) {
3729                            var events = options.dynamicEvents["woo_remove_from_cart"][item_hash];
3730                            Utils.fireEventForAllPixel("onWooRemoveFromCartEvent",events)
3731                        }
3732
3733                    }
3734
3735                });
3736            }
3737        }
3738
3739        // setup EDD events
3740        if (options.edd.enabled) {
3741
3742            // EDD AddToCart
3743            if (options.dynamicEvents.hasOwnProperty("edd_add_to_cart_on_button_click")) {
3744
3745                $('form.edd_download_purchase_form .edd-add-to-cart').on("click",function (e) {
3746
3747                    var $button = $(this);
3748                    var $form = $button.closest('form');
3749                    var variable_price = $button.data('variablePrice'); // yes/no
3750                    var price_mode = $button.data('priceMode'); // single/multi
3751                    var ids = [];
3752                    var quantities = [];
3753                    var qty;
3754                    var id;
3755
3756                    if (variable_price === 'yes' && price_mode === 'multi') {
3757
3758                        id = $form.find('input[name="download_id"]').val();
3759
3760                        // get selected variants
3761                        $.each($form.find('input[name="edd_options[price_id][]"]:checked'), function (i, el) {
3762                            ids.push(id + '_' + $(el).val());
3763                        });
3764
3765                        // get qty for selected variants
3766                        $.each(ids, function (i, variant_id) {
3767
3768                            var variant_index = variant_id.split('_', 2);
3769                            qty = $form.find('input[name="edd_download_quantity_' + variant_index[1] + '"]').val();
3770
3771                            if (typeof qty !== 'undefined') {
3772                                quantities.push(qty);
3773                            } else {
3774                                quantities.push(1);
3775                            }
3776
3777                        });
3778
3779                    } else if (variable_price === 'yes' && price_mode === 'single') {
3780
3781                        id = $form.find('input[name="download_id"]').val();
3782                        ids.push(id + '_' + $form.find('input[name="edd_options[price_id][]"]:checked').val());
3783
3784                        qty = $form.find('input[name="edd_download_quantity"]').val();
3785
3786                        if (typeof qty !== 'undefined') {
3787                            quantities.push(qty);
3788                        } else {
3789                            quantities.push(1);
3790                        }
3791
3792                    } else {
3793
3794                        ids.push($button.data('downloadId'));
3795
3796                        qty = $form.find('input[name="edd_download_quantity"]').val();
3797
3798                        if (typeof qty !== 'undefined') {
3799                            quantities.push(qty);
3800                        } else {
3801                            quantities.push(1);
3802                        }
3803                    }
3804
3805                    // fire event for each download/variant
3806                    $.each(ids, function (i, download_id) {
3807
3808                        var q = parseInt(quantities[i]);
3809                        var variant_index = download_id.toString().split('_', 2);
3810                        var price_index;
3811
3812                        if (variant_index.length === 2) {
3813                            download_id = variant_index[0];
3814                            price_index = variant_index[1];
3815                        }
3816
3817                        Facebook.onEddAddToCartOnButtonEvent(download_id, price_index, q);
3818                        Analytics.onEddAddToCartOnButtonEvent(download_id, price_index, q);
3819                        GTM.onEddAddToCartOnButtonEvent(download_id, price_index, q);
3820                        Pinterest.onEddAddToCartOnButtonEvent(download_id, price_index, q);
3821                        Bing.onEddAddToCartOnButtonEvent(download_id, price_index, q);
3822	                    Reddit.onEddAddToCartOnButtonEvent(download_id, price_index, q);
3823                    });
3824
3825                });
3826
3827            }
3828
3829
3830            // EDD RemoveFromCart
3831            if (options.dynamicEvents.hasOwnProperty("edd_remove_from_cart") ) {
3832
3833                $('form#edd_checkout_cart_form .edd_cart_remove_item_btn').on("click",function (e) {
3834
3835                    var href = $(this).attr('href');
3836                    if(href) {
3837                        var key = href.substring(href.indexOf('=') + 1).charAt(0);
3838                        if (options.dynamicEvents.edd_remove_from_cart.hasOwnProperty(key)) {
3839                            var events = options.dynamicEvents.edd_remove_from_cart[key];
3840                            Utils.fireEventForAllPixel("onEddRemoveFromCartEvent",events)
3841                        }
3842                    }
3843                });
3844
3845            }
3846
3847        }
3848
3849        // setup Comment Event
3850        if (options.dynamicEvents.hasOwnProperty("automatic_event_c
3850omment")
3851        ) {
3852
3853            $('form.comment-form').on("submit",function () {
3854                if (options.dynamicEvents.hasOwnProperty("automatic_event_comment")) {
3855                    var pixels = Object.keys(options.dynamicEvents.automatic_event_comment);
3856                    for (var i = 0; i < pixels.length; i++) {
3857	                    var event = Utils.clone(options.dynamicEvents.automatic_event_comment[pixels[i]]);
3858	                    if ( pixels[i] !== 'reddit') {
3859		                    Utils.copyProperties(Utils.getRequestParams(), event.params);
3860	                    }
3861                        getPixelBySlag(pixels[i]).onCommentEvent(event);
3862                    }
3863                }
3864            });
3865
3866        }
3867
3868
3869        // setup Form Event
3870        if ( options.dynamicEvents.hasOwnProperty("automatic_event_form")) {
3871
3872            $(document).onFirst('submit', 'form', function (e) {
3873
3874                var $form = $(this);
3875
3876                // exclude WP forms
3877                const formClass = $form.attr('class') || '';
3878                const formRole = ($form.attr('role') || '').toLowerCase();
3879                const formId = $form.attr('id');
3880
3881                if (
3882                    $form.hasClass('comment-form') ||
3883                    $form.hasClass('search-form') ||
3884                    $form.hasClass('woocommerce-ordering') ||
3885                    formClass.toLowerCase().includes('search') || formClass.toLowerCase().includes('add-to-cart') ||
3886                    formRole === 'search' ||
3887                    formId === 'adminbarsearch'
3888                ) {
3889                    return;
3890                }
3891
3892                // exclude Woo forms
3893                if ($form.hasClass('woocommerce-product-search') || $form.hasClass('cart') || $form.hasClass('woocommerce-cart-form') ||
3894                    $form.hasClass('woocommerce-shipping-calculator') || $form.hasClass('checkout') || $form.hasClass('checkout_coupon')) {
3895                    return;
3896                }
3897
3898                // exclude EDD forms
3899                if ($form.hasClass('edd_form') || $form.hasClass('edd_download_purchase_form')) {
3900                    return;
3901                }
3902// exclude CF7 forms
3903                if ($form.hasClass('wpcf7-form')) {
3904                    return;
3905                }
3906                // exclude Forminator forms
3907                if ($form.hasClass('forminator-custom-form') || $form.hasClass('forminator_ajax')) {
3908                    return;
3909                }
3910                // exclude WPforms forms
3911                if ($form.hasClass('wpforms-form') || $form.hasClass('wpforms-ajax-form')) {
3912                    return;
3913                }
3914                // exclude Formidable forms
3915                /*if ($form.hasClass('frm-show-form')) {
3916                    return;
3917                }*/
3918                // exclude Ninja Forms forms
3919                if ($form.parent().hasClass('nf-form-layout')) {
3920                    return;
3921                }
3922                // exclude Fluent forms
3923                if ($form.hasClass('frm-fluent-form')) {
3924                    return;
3925                }
3926                if(!options.enable_success_send_form) {
3927                    var params = {
3928                        form_id: $form.attr('id'),
3929                        form_class: $form.attr('class'),
3930                        text: $form.find('[type="submit"]').is('input') ?
3931                            $form.find('[type="submit"]').val() : $form.find('[type="submit"]').text()
3932                    };
3933
3934                    if (options.dynamicEvents.hasOwnProperty("automatic_event_form")) {
3935                        var pixels = Object.keys(options.dynamicEvents.automatic_event_form);
3936                        for (var i = 0; i < pixels.length; i++) {
3937                            var event = Utils.clone(options.dynamicEvents.automatic_event_form[pixels[i]]);
3938
3939	                        if (pixels[i] === "tiktok" || pixels[i] === "reddit") {
3940                                getPixelBySlag(pixels[i]).fireEvent(event.name, event);
3941                            } else {
3942                                Utils.copyProperties(params, event.params,)
3943                                Utils.copyProperties(Utils.getRequestParam
3943s(), event.params);
3944                                getPixelBySlag(pixels[i]).onFormEvent(event);
3945                            }
3946                        }
3947                    }
3948                }
3949            });
3950
3951            document.addEventListener( 'wpcf7mailsent', function( event ) {
3952                var form_id = event.detail.contactFormId;
3953                sendFormAction($(event.target), form_id);
3954            }, false );
3955            //Forminator
3956            $(document).on( 'forminator:form:submit:success', function( event ){
3957                var form_id = $(event.target).find('input[name="form_id"]').val();
3958                sendFormAction($(event.target), form_id);
3959            });
3960
3961            //WPForm
3962            $('form.wpforms-form').on('wpformsAjaxSubmitSuccess', (event) => {
3963                var form_id = $(event.target).attr('data-formid');
3964                sendFormAction($(event.target), form_id);
3965            })
3966            $(document).on( 'frmFormComplete', function( event, form, response ) {
3967                const form_id = $(form).find('input[name="form_id"]').val();
3968                sendFormAction($(event.target), form_id);
3969            });
3970            // Ninja Forms
3971            $(document).onFirst('nfFormSubmitResponse', function (event, data) {
3972                const form_id = data.response.data.form_id;
3973                sendFormAction($(event.target), form_id);
3974            });
3975
3976            var fluentForms = $('form.frm-fluent-form');
3977            fluentForms.each(function() {
3978                var $form = $(this);
3979                $form.on('fluentform_submission_success', function(event) {
3980                    var $formItem = $(this);
3981                    var form_id = $formItem.attr('data-form_id');
3982                    sendFormAction($(event.target), form_id);
3983                });
3984            });
3985
3986        }
3987
3988
3989        // load pixel APIs
3990        Utils.loadPixels();
3991        // setup Enrich content
3992        if(Utils.isCheckoutPage()) {
3993            Utils.addCheckoutFields();
3994        }
3995    });
3996
3997    var sendFormAction = function (form_target, formId){
3998        var params = {
3999            form_id: formId,
4000            text: form_target.find('[type="submit"]').is('input') ? form_target.find('[type="submit"]').val() :
4001                form_target.find('.forminator-button-submit').text() != '' ? form_target.find('.forminator-button-submit').text() :
4002                    form_target.find('[type="submit"]').text()
4003        };
4004
4005        if (options.dynamicEvents.hasOwnProperty("automatic_event_form")) {
4006            var pixels = Object.keys(options.dynamicEvents.automatic_event_form);
4007            for (var i = 0; i < pixels.length; i++) {
4008                var event = options.dynamicEvents.automatic_event_form[pixels[i]];
4009                if (pixels[i] === "tiktok" || pixels[i] === "reddit") {
4010                    getPixelBySlag(pixels[i]).fireEvent(event.name, event);
4011                } else {
4012                    Utils.copyProperties(params, event.params)
4013                    Utils.copyProperties(Utils.getRequestParams(), event.params);
4014                    getPixelBySlag(pixels[i]).onFormEvent(event);
4015                }
4016            }
4017        }
4018    }
4019
4020}(jQuery, pysOptions);
4021
4022function pys_generate_token() {
4023    return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
4024        (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
4025    );
4026}
4027
4028function getBundlePriceOnSingleProduct(data) {
4029    var items_sum = 0;
4030    jQuery(".bundle_form .bundled_product").each(function(index){
4031        var id = jQuery(this).find(".cart").data("bundled_item_id");
4032        var item_price = data.prices[id];
4033        var item_quantity = jQuery(this).find(".bundled_qty").val();
4034        if(!jQuery(this).hasClass("bundled_item_optional") ||
4035            jQuery(this).find(".bundled_product_optional_checkbox input").prop('checked')) {
4036            items_sum += item_price*item_quantity;
4037        }
4038    });
4039    return items_sum;
4040}
4041function getUrlParameter(sParam) {
4042    var sPageURL = window.location.search.substring(1),
4043        sURLVariables = sPageURL.split('&'),
4044        sParameterName,
4045        i;
4046
4047    for (i = 0; i < sURLVariables.length; i++) {
4048        sParameterName = sURLVariables[i].split('=');
4049
4050        if (sParameterName[0] === sParam) {
4051            return sParameterName[1] === undefined ? true : decodeURIComponent(sParameterName[1]);
4052        }
4053    }
4054    return false;
4055};
4056function getCookieYes(key) {
4057    const cookiesObj = document.cookie
4058        .split(";")
4059        .reduce((ac, cv) => {
4060            const [k, v] = cv.split("=");
4061            if (k && v) ac[k.trim()] = v;
4062            return ac;
4063        }, {});
4064    const consentCookie = cookiesObj["cookieyes-consent"] || cookiesObj["wt_consent"];
4065    if (!consentCookie) return undefined;
4066    const { [key]: value } = consentCookie
4067        .split(",")
4068        .reduce((obj, pair) => {
4069            const [k, v] = pair.split(":");
4070            if (k && v) obj[k] = v;
4071            return obj;
4072        }, {});
4073    return value;
4074}
4075function getRootDomain(useSubdomain = false) {
4076    const hostname = window.location.hostname; // Get the current hostname
4077    // Check if tldjs is defined before using it
4078    if (typeof tldjs === "undefined") {
4079        console.warn("tldjs is not defined");
4080        return hostname; // Return hostname as a fallback
4081    }
4082
4083    const rootDomain = tldjs.getDomain(hostname); // Use tldjs to extract the root domain
4084
4085    // Return the root domain with or without a leading dot based on useSubdomain
4086    return rootDomain ? (useSubdomain ? '.' + rootDomain : rootDomain) : hostname;
4087}

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.