PageSourceSearch

https://www.lupa.co.il/wp-content/plugins/pixelyoursite/dist/scripts/public.js?ver=11.2.0.4

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

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.