PageSourceSearch

https://www.zuckedbook.com/wp-content/plugins/pixelyoursite-pro/dist/scripts/public.js?ver=7.1.2

js zuckedbook.com collected 2026-09-28 11:14:07 UTC 90,908 bytes, 2,715 lines download raw bytes

1/* global pysOptions */
2
3// https://bitbucket.org/pixelyoursite/pys_pro_7/issues/7/possible-ie-11-error
4// https://tc39.github.io/ecma262/#sec-array.prototype.includes
5if (!Array.prototype.includes) {
6    Object.defineProperty(Array.prototype, 'includes', {
7        value: function (searchElement, fromIndex) {
8
9            if (this == null) {
10                throw new TypeError('"this" is null or not defined');
11            }
12
13            // 1. Let O be ? ToObject(this value).
14            var o = Object(this);
15
16            // 2. Let len be ? ToLength(? Get(O, "length")).
17            var len = o.length >>> 0;
18
19            // 3. If len is 0, return false.
20            if (len === 0) {
21                return false;
22            }
23
24            // 4. Let n be ? ToInteger(fromIndex).
25            //    (If fromIndex is undefined, this step produces the value 0.)
26            var n = fromIndex | 0;
27
28            // 5. If n ≥ 0, then
29            //  a. Let k be n.
30            // 6. Else n < 0,
31            //  a. Let k be len + n.
32            //  b. If k < 0, let k be 0.
33            var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
34
35            function sameValueZero(x, y) {
36                return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));
37            }
38
39            // 7. Repeat, while k < len
40            while (k < len) {
41                // a. Let elementK be the result of ? Get(O, ! ToString(k)).
42                // b. If SameValueZero(searchElement, elementK) is true, return true.
43                if (sameValueZero(o[k], searchElement)) {
44                    return true;
45                }
46                // c. Increase k by 1.
47                k++;
48            }
49
50            // 8. Return false
51            return false;
52        }
53    });
54}
55
56!function ($, options) {
57
58    if (options.debug) {
59        console.log('PYS:', options);
60    }
61
62    var dummyPinterest = function () {
63
64        /**
65         * Public API
66         */
67        return {
68
69            isEnabled: function () {
70            },
71
72            disable: function () {
73            },
74
75            loadPixel: function () {
76            },
77
78            fireEvent: function (name, data) {
79                return false;
80            },
81
82            onAdSenseEvent: function () {
83            },
84
85            onClickEvent: function (params) {
86            },
87
88            onWatchVideo: function (params) {
89            },
90
91            onCommentEvent: function () {
92            },
93
94            onFormEvent: function (params) {
95            },
96
97            onDownloadEvent: function (params) {
98            },
99
100            onWooAddToCartOnButtonEvent: function (product_id) {
101            },
102
103            onWooAddToCartOnSingleEvent: function (product_id, qty, is_variable, is_external, $form) {
104            },
105
106            onWooRemoveFromCartEvent: function (cart_item_hash) {
107            },
108
109            onWooAffiliateEvent: function (product_id) {
110            },
111
112            onWooPayPalEvent: function () {
113            },
114
115            onEddAddToCartOnButtonEvent: function (download_id, price_index, qty) {
116            },
117
118            onEddRemoveFromCartEvent: function (item) {
119            }
120
121        }
122
123    }();
124
125    var Utils = function (options) {
126
127        var Pinterest = dummyPinterest;
128
129        var gtag_loaded = false;
130
131        function loadPixels() {
132
133            if (!options.gdpr.all_disabled_by_api) {
134
135                if (!options.gdpr.facebook_disabled_by_api) {
136                    Facebook.loadPixel();
137                }
138
139                if (!options.gdpr.analytics_disabled_by_api) {
140                    Analytics.loadPixel();
141                }
142
143                if (!options.gdpr.google_ads_disabled_by_api) {
144                    GAds.loadPixel();
145                }
146
147                if (!options.gdpr.pinterest_disabled_by_api) {
148                    Pinterest.loadPixel();
149                }
150
151            }
152
153        }
154
155        /**
156         * WATCHVIDEO UTILS
157         */
158
159        function isJSApiAttrEnabled(url) {
160            return url.indexOf('enablejsapi') > -1;
161        }
162
163        function isOriginAttrEnabled(url) {
164            return url.indexOf('origin') > -1;
165        }
166
167        // Returns key/value pairs of percentages: number of seconds to achieve
168        function getVideoCompletionMarks(duration) {
169
170            var marks = {};
171            var points = [0, 10, 50, 90, 100];
172
173            for (var i = 0; i < points.length; i++) {
174
175                var _point = points[i];
176                var _mark = _point + '%';
177                var _time = duration * _point / 100;
178
179                if (_point === 100) {
180                    _time = _time - 1;
181                }
182
183                // 10% => 123
184                marks[_mark] = Math.floor(_time);
185
186            }
187
188            return marks;
189
190        }
191
192        // Determine if the element is a YouTube video or not
193        function tagIsYouTubeVideo(tag) {
194            var src = tag.src || '';
195            return src.indexOf('youtube.com/embed/') > -1 || src.indexOf('youtube.com/v/') > -1;
196        }
197
198        // Turn embed objects into iframe objects and ensure they have the right parameters
199        function normalizeYouTubeIframe(tag) {
200
201            var loc = window.location;
202            var a = document.createElement('a');
203            a.href = tag.src;
204            a.hostname = 'www.youtube.com';
205            a.protocol = loc.protocol;
206            var tmpPathname = a.pathname.charAt(0) === '/' ? a.pathname : '/' + a.pathname; // IE10 shim
207
208            if (!isJSApiAttrEnabled(a.search)) {
209                a.search = (a.search.length > 0 ? a.search + '&' : '') + 'enablejsapi=1';
210            }
211
212            // for security reasons, YouTube wants an origin parameter set that matches our hostname
213            if (!isOriginAttrEnabled(a.search) && loc.hostname.indexOf('localhost') === -1) {
214
215                var port = loc.port ? ':' + loc.port : '';
216                var origin = loc.protocol + '%2F%2F' + loc.hostname + port;
217
218                a.search = a.search + '&origin=' + origin;
219
220            }
221
222            if (tag.type === 'application/x-shockwave-flash') {
223
224                var newIframe = document.createElement('iframe');
225                newIframe.height = tag.height;
226                newIframe.width = tag.width;
227                tmpPathname = tmpPathname.replace('/v/', '/embed/');
228
229                tag.parentNode.parentNode.replaceChild(newIframe, tag.parentNode);
230
231                tag = newIframe;
232
233            }
234
235            a.pathname = tmpPathname;
236
237            if (tag.src !== a.href + a.hash) {
238                tag.src = a.href + a.hash;
239            }
240
241            return tag;
242
243        }
244
245        // Add event handlers for events emitted by the YouTube API
246        function addYouTubeEvents(iframe) {
247
248            var player = YT.get(iframe.id);
249
250            if (!player) {
251                player = new YT.Player(iframe, {});
252            }
253
254            if (typeof iframe.pauseFlag === 'undefined') {
255
256                iframe.pauseFlag = false;
257                player.addEventListener('onStateChange', function (evt) {
258                    onYouTubePlayerStateChange(evt, iframe);
259                });
260
261            }
262
263        }
264
265        // Event handler for events emitted from the YouTube API
266        function onYouTubePlayerStateChange(evt, iframe) {
267
268            var stateIndex = evt.data;
269            var player = evt.target;
270            var targetVideoUrl = player.getVideoUrl();
271            var targetVideoId = targetVideoUrl.match(/[?&]v=([^&#]*)/)[1]; // Extract the ID
272            var playerState = player.getPlayerState();
273            var marks = getVideoCompletionMarks(player.getDuration());
274
275            iframe.playTracker = iframe.playTracker || {};
276
277            if (playerState === YT.PlayerState.PLAYING && !iframe.timer) {
278
279                clearInterval(iframe.timer);
280
281                // check every second to see if we've hit any of our percentage viewed marks
282                iframe.timer = setInterval(function () {
283                    checkYouTubeCompletion(player, marks, iframe.videoId);
284                }, 1000);
285
286            } else {
287
288                clearInterval(iframe.timer);
289                iframe.timer = false;
290
291            }
292
293            // playlist edge-case handler
294            if (stateIndex === YT.PlayerState.PLAYING) {
295                iframe.playTracker[targetVideoId] = true;
296                iframe.videoId = targetVideoId;
297                iframe.pauseFlag = false;
298            }
299
300            if (!iframe.playTracker[iframe.videoId]) {
301                return false;   // this video hasn't started yet, so this is spam
302            }
303
304            if (stateIndex === YT.PlayerState.PAUSED) {
305
306                if (!iframe.pauseFlag) {
307                    iframe.pauseFlag = true;
308                } else {
309                    return false;   // we don't want to fire consecutive pause events
310                }
311
312            }
313
314        }
315
316        // Trigger event if YouTube video mark was reached
317        function checkYouTubeCompletion(player, marks, videoId) {
318
319            var currentTime = player.getCurrentTime();
320
321            player[videoId] = player[videoId] || {};
322
323            for (var key in marks) {
324
325                if (marks[key] <= currentTime && !player[videoId][key]) {
326                    player[videoId][key] = true;
327
328                    var data = player.getVideoData();
329
330                    if (key === '0%') {
331                        key = 'play';
332                    }
333
334                    var params = {
335                        video_type: 'youtube',
336                        video_id: videoId,
337                        video_title: data.title,
338                        event_trigger: key
339                    };
340
341                    Facebook.onWatchVideo(params);
342                    Analytics.onWatchVideo(params);
343                    GAds.onWatchVideo(params);
344                    Pinterest.onWatchVideo(params);
345
346                }
347
348            }
349
350        }
351
352        // Determine if the element is a Vimeo video or not
353        function tagIsVimeoVideo(tag) {
354            var src = tag.src || '';
355            return src.indexOf('player.vimeo.com/video/') > -1;
356        }
357
358        // Trigger event if Vimeo video mark was reached
359        function checkVimeoCompletion(player) {
360
361            player.getCurrentTime().then(function (seconds) {
362
363                for (var key in player.pysMarks) {
364
365                    if (player.pysMarks[key] <= seconds && !player.pysCompletedMarks[key]) {
366
367                        player.pysCompletedMarks[key] = true;
368
369                        if (key === '0%') {
370                            key = 'play';
371                        }
372
373                        var params = {
374                            video_type: 'vimeo',
375                            video_id: player.pysVideoId,
376                            video_title: player.pysVideoTitle,
377                            event_trigger: key
378                        };
379
380                        Facebook.onWatchVideo(params);
381                        Analytics.onWatchVideo(params);
382                        GAds.onWatchVideo(params);
383                        Pinterest.onWatchVideo(params);
384
385                    }
386
387                }
388
389            });
390
391        }
392
393        /**
394         * COOKIES UTILS
395         */
396
397        var utmTerms = ['utm_source', 'utm_media', 'utm_campaign', 'utm_term', 'utm_content'];
398
399        var requestParams = [];
400
401        function validateEmail(email) {
402            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,}))$/;
403            return re.test(email);
404        }
405
406        function getTrafficSource() {
407
408            try {
409
410                var referrer = document.referrer.toString(),
411                    source;
412
413                var direct = referrer.length === 0;
414                var internal = direct ? false : referrer.indexOf(options.siteUrl) === 0;
415                var external = !direct && !internal;
416                var cookie = typeof Cookies.get('pysTrafficSource') === 'undefined' ? false : Cookies.get('pysTrafficSource');
417
418                if (external === false) {
419                    source = cookie ? cookie : 'direct';
420                } else {
421                    source = cookie && cookie === referrer ? cookie : referrer;
422                }
423                
424                if (source !== 'direct') {
425
426                    var url = document.createElement('a');
427                    url.href = source;
428
429                    // leave only domain (Issue #70)
430                    return url.hostname;
431
432                } else {
433                    return source;
434                }
435
436            } catch (e) {
437                console.error(e);
438                return 'direct';
439            }
440
441        }
442
443        /**
444         * Return query variables object with where property name is query variable
445         * and property value is query variable value.
446         */
447        function getQueryVars() {
448
449            try {
450
451                var result = {}, tmp = [];
452
453                window.location.search
454                    .substr(1)
455                    .split("&")
456                    .forEach(function (item) {
457
458                        tmp = item.split('=');
459
460                        if (tmp.length > 1) {
461                            result[tmp[0]] = tmp[1];
462                        }
463
464                    });
465
466                return result;
467
468            } catch (e) {
469                console.error(e);
470                return {};
471            }
472
473        }
474
475        /**
476         * Return UTM terms from request query variables or from cookies.
477         */
478        function getUTMs() {
479
480            try {
481
482                var terms = [];
483                var queryVars = getQueryVars();
484
485                $.each(utmTerms, function (index, name) {
486
487                    var value;
488
489                    if (Cookies.get('pys_' + name)) {
490                        value = Cookies.get('pys_' + name);
491                    } else if (queryVars.hasOwnProperty(name)) {
492                        value = queryVars[name];
493                    }
494
495                    // do not allow email in request params (Issue #70)
496                    terms[name] = filterEmails(value);
497
498                });
499
500                return terms;
501
502            } catch (e) {
503                console.error(e);
504                return [];
505            }
506
507        }
508
509        function filterEmails(value) {
510            return validateEmail(value) ? undefined : value;
511        }
512
513        /**
514         * PUBLIC API
515         */
516        return {
517
518            filterEmails: function (value) {
519                return filterEmails(value);
520            },
521
522            setupPinterestObject: function () {
523                Pinterest = window.pys.Pinterest || Pinterest;
524                return Pinterest;
525            },
526
527            // Clone all object members to another and return it
528            copyProperties: function (from, to) {
529                for (var key in from) {
530                    to[key] = from[key];
531                }
532                return to;
533            },
534
535            // Returns array of elements with given tag name
536            getTagsAsArray: function (tag) {
537                return [].slice.call(document.getElementsByTagName(tag));
538            },
539
540            /**
541             * Load and initialize YouTube API
542             *
543             * @link: https://developers.google.com/youtube/iframe_api_reference
544             */
545            initYouTubeAPI: function () {
546
547                // maybe load YouTube JS API
548                if (typeof window.YT === 'undefined') {
549                    var tag = document.createElement('script');
550                    tag.src = '//www.youtube.com/iframe_api';
551                    var firstScriptTag = document.getElementsByTagName('script')[0];
552                    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
553                }
554
555                // initialize when API is ready
556                window.onYouTubeIframeAPIReady = function () {
557
558                    // collect all possible YouTube tags
559                    var potentialVideos = Utils.getTagsAsArray('iframe').concat(Utils.getTagsAsArray('embed'));
560
561                    // turn videos into trackable videos with events
562                    for (var i = 0; i < potentialVideos.length; i++) {
563                        if (tagIsYouTubeVideo(potentialVideos[i])) {
564                            var iframe = normalizeYouTubeIframe(potentialVideos[i]);
565                            addYouTubeEvents(iframe);
566                        }
567                    }
568
569                    // bind to dynamically added videos
570                    $(document).load(function () {
571
572                        var el = evt.target || evt.srcElement;
573                        var isYT = checkIfYouTubeVideo(el);
574
575                        // We only bind to iFrames with a YouTube URL with the enablejsapi=1 and
576                        // origin=<<hostname>> parameters
577                        if (el.tagName === 'IFRAME' && isYT && isJSApiAttrEnabled(el.src) && isOriginAttrEnabled(el.src)) {
578                            addYouTubeEvents(el);
579                        }
580
581                    });
582
583                };
584
585            },
586
587            /**
588             * Load and initialize Vimeo API
589             *
590             * @link: https://github.com/vimeo/player.js
591             */
592            initVimeoAPI: function () {
593
594                $(document).ready(function () {
595
596                    var potentialVideos = Utils.getTagsAsArray('iframe').concat(Utils.getTagsAsArray('embed'));
597
598                    for (var i = 0; i < potentialVideos.length; i++) {
599
600                        if (!tagIsVimeoVideo(potentialVideos[i])) {
601                            continue;
602                        }
603
604                        var player = new Vimeo.Player(potentialVideos[i]);
605
606                        player.getDuration().then(function (seconds) {
607                            player.pysMarks = getVideoCompletionMarks(seconds);
608                        });
609
610                        player.getVideoTitle().then(function (title) {
611                            player.pysVideoTitle = title;
612                        });
613
614                        player.getVideoId().then(function (id) {
615                            player.pysVideoId = id;
616                        });
617
618                        player.pysCompletedMarks = {};
619
620                        player.on('play', function () {
621
622                            if (this.pysTimer) {
623                                return;
624                            }
625
626                            clearInterval(this.pysTimer);
627
628                            var player = this;
629
630                            this.pysTimer = setInterval(function () {
631                                checkVimeoCompletion(player);
632                            }, 1000);
633
634                        });
635
636                        player.on('pause', function () {
637                            clearInterval(this.pysTimer);
638                            this.pysTimer = false;
639                        });
640
641                        player.on('ended', function () {
642                            clearInterval(this.pysTimer);
643                            this.pysTimer = false;
644                        });
645
646                    }
647
648                });
649
650            },
651
652            manageCookies: function () {
653
654                try {
655
656                    var expires = 0.5; // half day
657                    var source = getTrafficSource();
658
659                    // manage traffic source cookie
660                    if (source !== 'direct') {
661                        Cookies.set('pysTrafficSource', source, {expires: expires});
662                    } else {
663                        Cookies.remove('pysTrafficSource');
664                    }
665
666                    var queryVars = getQueryVars();
667
668                    // manage utm cookies
669                    $.each(utmTerms, function (index, name) {
670
671                        if (Cookies.get('pys_' + name) === undefined && queryVars.hasOwnProperty(name)) {
672                            Cookies.set('pys_' + name, queryVars[name], {expires: expires});
673                        }
674
675                    });
676
677                } catch (e) {
678                    console.error(e);
679                }
680
681            },
682
683            initializeRequestParams: function () {
684
685                if (options.trackTrafficSource) {
686                    requestParams.traffic_source = getTrafficSource();
687                }
688
689                if (options.trackUTMs) {
690
691                    var utms = getUTMs();
692
693                    $.each(utmTerms, function (index, term) {
694                        if (term in utms) {
695                            requestParams[term] = utms[term];
696                        }
697                    });
698
699                }
700
701                var date = new Date(),
702                    days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
703                    months = ['January', 'February', 'March', 'April', 'May', 'June',
704                        'July', 'August', 'September', 'October', 'November', 'December'
705                    ],
706                    hours = ['00-01', '01-02', '02-03', '03-04', '04-05', '05-06', '06-07', '07-08',
707                        '08-09', '09-10', '10-11', '11-12', '12-13', '13-14', '14-15', '15-16', '16-17',
708                        '17-18', '18-19', '19-20', '20-21', '21-22', '22-23', '23-24'
709                    ];
710
711                requestParams.event_day = days[date.getDay()];
712                requestParams.event_month = months[date.getMonth()];
713                requestParams.event_hour = hours[date.getHours()];
714
715            },
716
717            getRequestParams: function () {
718                return requestParams;
719            },
720
721            /**
722             * DOWNLOAD DOCS
723             */
724
725            getLinkExtension: function (link) {
726
727                // Remove anchor, query string and everything before last slash
728                link = link.substring(0, (link.indexOf("#") === -1 ) ? link.length : link.indexOf("#"));
729                link = link.substring(0, (link.indexOf("?") === -1 ) ? link.length : link.indexOf("?"));
730                link = link.substring(link.lastIndexOf("/") + 1, link.length);
731
732                // If there's a period left in the URL, then there's a extension
733                if (link.length > 0 && link.indexOf('.') !== -1) {
734                    link = link.substring(link.indexOf(".") + 1); // Remove everything but what's after the first period
735                    return link;
736                } else {
737                    return "";
738                }
739            },
740
741            getLinkFilename: function (link) {
742
743                // Remove anchor, query string and everything before last slash
744                link = link.substring(0, (link.indexOf("#") === -1 ) ? link.length : link.indexOf("#"));
745                link = link.substring(0, (link.indexOf("?") === -1 ) ? link.length : link.indexOf("?"));
746                link = link.substring(link.lastIndexOf("/") + 1, link.length);
747
748                // If there's a period left in the URL, then there's a extension
749                if (link.length > 0 && link.indexOf('.') !== -1) {
750                    return link;
751                } else {
752                    return "";
753                }
754            },
755
756            /**
757             * CUSTOM EVENTS
758             */
759
760            setupMouseOverClickEvents: function (eventId, triggers) {
761
762                // Non-default binding used to avoid situations when some code in external js
763                // stopping events propagation, eg. returns false, and our handler will never called
764                $(document).onFirst('mouseover', triggers.join(','), function () {
765
766                    // do not fire event multiple times
767                    if ($(this).hasClass('pys-mouse-over-' + eventId)) {
768                        return true;
769                    } else {
770                        $(this).addClass('pys-mouse-over-' + eventId);
771                    }
772
773                    Utils.fireDynamicEvent(eventId);
774
775                });
776
777            },
778
779            setupCSSClickEvents: function (eventId, triggers) {
780
781                // Non-default binding used to avoid situations when some code in external js
782                // stopping events propagation, eg. returns false, and our handler will never called
783                $(document).onFirst('click', triggers.join(','), function () {
784                    Utils.fireDynamicEvent(eventId);
785                });
786
787            },
788
789            setupURLClickEvents: function () {
790
791                // Non-default binding used to avoid situations when some code in external js
792                // stopping events propagation, eg. returns false, and our handler will never called
793                $('a[data-pys-event-id]').onFirst('click', function (evt) {
794
795                    $(this).attr('data-pys-event-id').split(',').forEach(function (eventId) {
796
797                        eventId = parseInt(eventId);
798
799                        if (isNaN(eventId) === false) {
800                            Utils.fireDynamicEvent(eventId);
801                        }
802
803                    });
804
805                });
806
807            },
808
809            setupScrollPosEvents: function (eventId, triggers) {
810
811                var scrollPosThresholds = {},
812                    docHeight = $(document).height() - $(window).height();
813
814                // convert % to absolute positions
815                $.each(triggers, function (index, scrollPos) {
816
817                    // convert % to pixels
818                    scrollPos = docHeight * scrollPos / 100;
819                    scrollPos = Math.round(scrollPos);
820
821                    scrollPosThresholds[scrollPos] = eventId;
822
823                });
824
825                $(document).scroll(function () {
826
827                    var scrollPos = $(window).scrollTop();
828
829                    $.each(scrollPosThresholds, function (threshold, eventId) {
830
831                        // position has not reached yes
832                        if (scrollPos <= threshold) {
833                            return true;
834                        }
835
836                        // fire event only once
837                        if (eventId === null) {
838                            return true;
839                        } else {
840                            scrollPosThresholds[threshold] = null;
841                        }
842
843                        Utils.fireDynamicEvent(eventId);
844
845                    });
846
847                });
848
849            },
850
851            /**
852             * Events
853             */
854
855            fireDynamicEvent: function (eventId) {
856
857                if (!options.dynamicEventsParams.hasOwnProperty(eventId)) {
858                    return;
859                }
860
861                var event = {};
862
863                if (options.dynamicEventsParams[eventId].hasOwnProperty('facebook')) {
864
865                    event = Utils.copyProperties(options.dynamicEventsParams[eventId]['facebook'], {});
866                    Facebook.fireEvent(event.name, {params: event.params});
867
868                }
869
870                if (options.dynamicEventsParams[eventId].hasOwnProperty('ga')) {
871
872                    event = Utils.copyProperties(options.dynamicEventsParams[eventId]['ga'], {});
873                    Analytics.fireEvent(event.action, {params: event.params});
874
875                }
876
877                if (options.dynamicEventsParams[eventId].hasOwnProperty('google_ads')) {
878
879                    event = Utils.copyProperties(options.dynamicEventsParams[eventId]['google_ads'], {});
880                    GAds.fireEvent(event.action, {params: event.params, ids: event.i
880ds});
881
882                }
883
884                if (options.dynamicEventsParams[eventId].hasOwnProperty('pinterest')) {
885
886                    event = Utils.copyProperties(options.dynamicEventsParams[eventId]['pinterest'], {});
887                    Pinterest.fireEvent(event.name, {params: event.params});
888
889                }
890
891            },
892
893            fireStaticEvents: function (pixel) {
894
895                if (options.staticEvents.hasOwnProperty(pixel)) {
896
897                    $.each(options.staticEvents[pixel], function (eventName, events) {
898                        $.each(events, function (index, eventData) {
899
900                            eventData.fired = eventData.fired || false;
901
902                            if (!eventData.fired) {
903
904                                var fired = false;
905
906                                // fire event
907                                if ('facebook' === pixel) {
908                                    fired = Facebook.fireEvent(eventName, eventData);
909                                } else if ('ga' === pixel) {
910                                    fired = Analytics.fireEvent(eventName, eventData);
911                                } else if ('google_ads' === pixel) {
912                                    fired = GAds.fireEvent(eventName, eventData);
913                                } else if ('pinterest' === pixel) {
914                                    fired = Pinterest.fireEvent(eventName, eventData);
915                                }
916
917                                // prevent event double event firing
918                                eventData.fired = fired;
919
920                            }
921
922                        });
923                    });
924
925                }
926
927            },
928
929            /**
930             * Load tag's JS
931             *
932             * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/
933             * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/custom-dims-mets
934             */
935            loadGoogleTag: function (id) {
936
937                if (!gtag_loaded) {
938
939                    (function (window, document, src) {
940                        var a = document.createElement('script'),
941                            m = document.getElementsByTagName('script')[0];
942                        a.async = 1;
943                        a.src = src;
944                        m.parentNode.insertBefore(a, m);
945                    })(window, document, '//www.googletagmanager.com/gtag/js?id=' + id);
946
947                    window.dataLayer = window.dataLayer || [];
948                    window.gtag = window.gtag || function gtag() {
949                        dataLayer.push(arguments);
950                    };
951
952                    gtag('js', new Date());
953
954                    gtag_loaded = true;
955
956                }
957
958            },
959
960            /**
961             * GDPR
962             */
963
964            loadPixels: function () {
965
966                if (options.gdpr.ajax_enabled) {
967
968                    // retrieves actual PYS GDPR filters values which allow to avoid cache issues
969                    $.get({
970                        url: options.ajaxUrl,
971                        dataType: 'json',
972                        data: {
973                            action: 'pys_get_gdpr_filters_values'
974                        },
975                        success: function (res) {
976
977                            if (res.success) {
978
979                                options.gdpr.all_disabled_by_api = res.data.all_disabled_by_api;
980                                options.gdpr.facebook_disabled_by_api = res.data.facebook_disabled_by_api;
981                                options.gdpr.analytics_disabled_by_api = res.data.analytics_disabled_by_api;
982                                options.gdpr.google_ads_disabled_by_api = res.data.google_ads_disabled_by_api;
983                                options.gdpr.pinterest_disabled_by_api = res.data.pinterest_disabled_by_api;
984
985                            }
986
987                            loadPixels();
988
989                        }
990                    });
991
992                } else {
993                    loadPixels();
994                }
995
996            },
997
998            consentGiven: function (pixel) {
999
1000                /**
1001                 * Cookiebot
1002                 */
1003                if (options.gdpr.cookiebot_integration_enabled && typeof Cookiebot !== 'undefined') {
1004
1005                    var cookiebot_consent_category = options.gdpr['cookiebot_' + pixel + '_consent_category'];
1006
1007                    if (options.gdpr[pixel + '_prior_consent_enabled']) {
1008                        if (Cookiebot.consented === false || Cookiebot.consent[cookiebot_consent_category]) {
1009                            return true;
1010                        }
1011                    } else {
1012                        if (Cookiebot.consent[cookiebot_consent_category]) {
1013                            return true;
1014                        }
1015                    }
1016
1017                    return false;
1018
1019                }
1020
1021                /**
1022                 * Ginger – EU Cookie Law
1023                 */
1024                if (options.gdpr.ginger_integration_enabled) {
1025
1026                    var ginger_cookie = Cookies.get('ginger-cookie');
1027
1028                    if (options.gdpr[pixel + '_prior_consent_enabled']) {
1029                        if (typeof ginger_cookie === 'undefined' || ginger_cookie === 'Y') {
1030                            return true;
1031                        }
1032                    } else {
1033                        if (ginger_cookie === 'Y') {
1034                            return true;
1035                        }
1036                    }
1037
1038                    return false;
1039
1040                }
1041
1042                /**
1043                 * Cookie Notice
1044                 */
1045                if (options.gdpr.cookie_notice_integration_enabled && typeof cnArgs !== 'undefined') {
1046
1047                    var cn_cookie = Cookies.get(cnArgs.cookieName);
1048
1049                    if (options.gdpr[pixel + '_prior_consent_enabled']) {
1050                        if (typeof cn_cookie === 'undefined' || cn_cookie === 'true') {
1051                            return true;
1052                        }
1053                    } else {
1054                        if (cn_cookie === 'true') {
1055                            return true;
1056                        }
1057                    }
1058
1059                    return false;
1060
1061                }
1062
1063                /**
1064                 * Cookie Law Info
1065                 */
1066                if (options.gdpr.cookie_law_info_integration_enabled) {
1067
1068                    var cli_cookie = Cookies.get('viewed_cookie_policy');
1069
1070                    if (options.gdpr[pixel + '_prior_consent_enabled']) {
1071                        if (typeof cli_cookie === 'undefined' || cli_cookie === 'yes') {
1072                            return true;
1073                        }
1074                    } else {
1075                        if (cli_cookie === 'yes') {
1076                            return true;
1077                        }
1078                    }
1079
1080                    return false;
1081
1082                }
1083
1084                return true;
1085
1086            },
1087
1088            setupGdprCallbacks: function () {
1089
1090                /**
1091                 * Cookiebot
1092                 */
1093                if (options.gdpr.cookiebot_integration_enabled && typeof Cookiebot !== 'undefined') {
1094
1095                    Cookiebot.onaccept = function () {
1096
1097                        if (Cookiebot.consent[options.gdpr.cookiebot_facebook_consent_category]) {
1098                            Facebook.loadPixel();
1099                        }
1100
1101                        if (Cookiebot.consent[options.gdpr.cookiebot_analytics_consent_category]) {
1102                            Analytics.loadPixel();
1103                        }
1104
1105                        if (Cookiebot.consent[options.gdpr.cookiebot_google_ads_consent_category]) {
1106                            GAds.loadPixel();
1107                        }
1108
1109                        if (Cookiebot.consent[options.gdpr.cookiebot_pinterest_consent_category]) {
1110                            Pinterest.loadPixel();
1111                        }
1112
1113                    };
1114
1115                    //@todo: +7.1.0+ check what exactly consent was withdrawed and disable corresponding pixel
1116                    Cookiebot.ondecline = function () {
1117                        Facebook.disable();
1118                        Analytics.disable();
1119                        GAds.disable();
1120                        Pinterest.disable();
1121                    };
1122
1123                }
1124
1125                /**
1126                 * Cookie Notice
1127                 */
1128                if (options.gdpr.cookie_notice_integration_enabled) {
1129
1130                    $(document).onFirst('click', '.cn-set-cookie', function () {
1131
1132                        if ($(this).data('cookie-set') === 'accept') {
1133                            Facebook.loadPixel();
1134                            Analytics.loadPixel();
1135                            GAds.loadPixel();
1136                            Pinterest.loadPixel();
1137                        } else {
1138                            Facebook.disable();
1139                            Analytics.disable();
1140                            GAds.disable();
1141                            Pinterest.disable();
1142                        }
1143
1144                    });
1145
1146                    $(document).onFirst('click', '.cn-revoke-cookie', function () {
1147                        Facebook.disable();
1148                        Analytics.disable();
1149                        GAds.disable();
1150                        Pinterest.disable();
1151                    });
1152
1153                }
1154
1155                /**
1156                 * Cookie Law Info
1157                 */
1158                if (options.gdpr.cookie_law_info_integration_enabled) {
1159
1160                    $(document).onFirst('click', '#cookie_action_close_header', function () {
1161                        Facebook.loadPixel();
1162                        Analytics.loadPixel();
1163                        GAds.loadPixel();
1164                        Pinterest.loadPixel();
1165                    });
1166
1167                    $(document).onFirst('click', '#cookie_action_close_header_reject', function () {
1168                        Facebook.disable();
1169                        Analytics.disable();
1170                        GAds.disable();
1171                        Pinterest.disable();
1172                    });
1173
1174                }
1175
1176            }
1177
1178        };
1179
1180    }(options);
1181
1182    var Facebook = function (options) {
1183
1184        var defaultEventTypes = [
1185            'PageView',
1186            'ViewContent',
1187            'Search',
1188            'AddToCart',
1189            'AddToWishlist',
1190            'InitiateCheckout',
1191            'AddPaymentInfo',
1192            'Purchase',
1193            'Lead',
1194
1195            'Subscribe',
1196            'CustomizeProduct',
1197            'FindLocation',
1198            'StartTrial',
1199            'SubmitApplication',
1200            'Schedule',
1201            'Contact',
1202            'Donate'
1203        ];
1204
1205        var initialized = false;
1206
1207        function fireEvent(name, data) {
1208
1209            var actionType = defaultEventTypes.includes(name) ? 'track' : 'trackCustom';
1210
1211            var params = {};
1212            Utils.copyProperties(data, params);
1213
1214            Utils.copyProperties(options.commonEventParams, params);
1215            Utils.copyProperties(Utils.getRequestParams(), params);
1216
1217            if (options.debug) {
1218                console.log('[Facebook] ' + name, params);
1219            }
1220
1221            fbq(actionType, name, params);
1222
1223        }
1224
1225        /**
1226         * Public API
1227         */
1228        return {
1229
1230            isEnabled: function () {
1231                return options.hasOwnProperty('facebook');
1232            },
1233
1234            disable: function () {
1235                initialized = false;
1236            },
1237
1238            /**
1239             * Load pixel's JS
1240             */
1241            loadPixel: function () {
1242
1243                if (initialized || !this.isEnabled() || !Utils.consentGiven('facebook')) {
1244                    return;
1245                }
1246
1247                !function (f, b, e, v, n, t, s) {
1248                    if (f.fbq) return;
1249                    n = f.fbq = function () {
1250                        n.callMethod ?
1251                            n.callMethod.apply(n, arguments) : n.queue.push(arguments)
1252                    };
1253                    if (!f._fbq) f._fbq = n;
1254                    n.push = n;
1255                    n.loaded = !0;
1256                    n.version = '2.0';
1257                    n.agent = 'dvpixelyoursite';
1258                    n.queue = [];
1259                    t = b.createElement(e);
1260                    t.async = !0;
1261                    t.src = v;
1262                    s = b.getElementsByTagName(e)[0];
1263                    s.parentNode.insertBefore(t, s)
1264                }(window,
1265                    document, 'script', 'https://connect.facebook.net/en_US/fbevents.js');
1266
1267                // initialize pixel
1268                options.facebook.pixelIds.forEach(function (pixelId) {
1269
1270                    if (options.facebook.removeMetadata) {
1271                        fbq('set', 'autoConfig', false, pixelId);
1272                    }
1273
1274                    fbq('init', pixelId, options.facebook.advancedMatching);
1275
1276                });
1277
1278                initialized = true;
1279
1280                Utils.fireStaticEvents('facebook');
1281
1282            },
1283
1284            fireEvent: function (name, data) {
1285
1286                if (!initialized || !this.isEnabled()) {
1287                    return false;
1288                }
1289
1290                data.delay = data.delay || 0;
1291                data.params = data.params || {};
1292
1293                if (data.delay === 0) {
1294
1295                    fireEvent(name, data.params);
1296
1297                } else {
1298
1299                    setTimeout(function (name, params) {
1300                        fireEvent(name, params);
1301                    }, data.delay * 1000, name, data.params);
1302
1303                }
1304
1305                return true;
1306
1307            },
1308
1309            onAdSenseEvent: function () {
1310
1311                if (initialized && this.isEnabled() && options.facebook.adSenseEventEnabled) {
1312                    this.fireEvent('AdSense', {
1313                        params: Utils.copyProperties(options.facebook.contentParams, {})
1314                    });
1315                }
1316
1317            },
1318
1319            onClickEvent: function (params) {
1320
1321                if (initialized && this.isEnabled() && options.facebook.clickEventEnabled) {
1322                    this.fireEvent('ClickEvent', {
1323                        params: Utils.copyProperties(options.facebook.contentParams, params)
1324                    });
1325                }
1326
1327            },
1328
1329            onWatchVideo: function (params) {
1330
1331                if (initialized && this.isEnabled() && options.facebook.watchVideoEnabled) {
1332                    this.fireEvent('WatchVideo', {
1333                        params: Utils.copyProperties(options.facebook.contentParam
1333s, params)
1334                    });
1335                }
1336
1337            },
1338
1339            onCommentEvent: function () {
1340
1341                if (initialized && this.isEnabled() && options.facebook.commentEventEnabled) {
1342
1343                    this.fireEvent('Comment', {
1344                        params: Utils.copyProperties(options.facebook.contentParams, {})
1345                    });
1346
1347                }
1348
1349            },
1350
1351            onFormEvent: function (params) {
1352
1353                if (initialized && this.isEnabled() && options.facebook.formEventEnabled) {
1354
1355                    this.fireEvent('Form', {
1356                        params: Utils.copyProperties(options.facebook.contentParams, params)
1357                    });
1358
1359                }
1360
1361            },
1362
1363            onDownloadEvent: function (params) {
1364
1365                if (initialized && this.isEnabled() && options.facebook.downloadEnabled) {
1366
1367                    this.fireEvent('Download', {
1368                        params: Utils.copyProperties(options.facebook.contentParams, params)
1369                    });
1370
1371                }
1372
1373            },
1374
1375            onWooAddToCartOnButtonEvent: function (product_id) {
1376
1377                if (window.pysWooProductData.hasOwnProperty(product_id)) {
1378                    if (window.pysWooProductData[product_id].hasOwnProperty('facebook')) {
1379
1380                        this.fireEvent('AddToCart', {
1381                            params: Utils.copyProperties(window.pysWooProductData[product_id]['facebook'], {})
1382                        });
1383
1384                    }
1385                }
1386
1387            },
1388
1389            onWooAddToCartOnSingleEvent: function (product_id, qty, is_variable, is_external, $form) {
1390
1391                window.pysWooProductData = window.pysWooProductData || [];
1392
1393                if (window.pysWooProductData.hasOwnProperty(product_id)) {
1394                    if (window.pysWooProductData[product_id].hasOwnProperty('facebook')) {
1395
1396                        if (is_variable && !options.facebook.wooVariableAsSimple) {
1397                            product_id = parseInt($form.find('input[name="variation_id"]').val());
1398                        }
1399
1400                        var params = Utils.copyProperties(window.pysWooProductData[product_id]['facebook'], {});
1401
1402                        // maybe customize value option
1403                        if (options.woo.addToCartOnButtonValueEnabled && options.woo.addToCartOnButtonValueOption !== 'global') {
1404                            params.value = params.value * qty;
1405                        }
1406
1407                        // only when non Facebook for WooCommerce logic used
1408                        if (params.hasOwnProperty('contents')) {
1409                            params.contents[0].quantity = qty;
1410                        }
1411
1412                        var event_name = is_external ? options.woo.affiliateEventName : 'AddToCart';
1413
1414                        this.fireEvent(event_name, {
1415                            params: params
1416                        });
1417
1418                    }
1419                }
1420
1421            },
1422
1423            onWooRemoveFromCartEvent: function (cart_item_hash) {
1424
1425                window.pysWooRemoveFromCartData = window.pysWooRemoveFromCartData || [];
1426
1427                if (window.pysWooRemoveFromCartData[cart_item_hash].hasOwnProperty('facebook')) {
1428
1429                    this.fireEvent('RemoveFromCart', {
1430                        params: Utils.copyProperties(window.pysWooRemoveFromCartData[cart_item_hash]['facebook'], {})
1431                    });
1432
1433                }
1434
1435            },
1436
1437            onWooAffiliateEvent: function (product_id) {
1438
1439                if (window.pysWooProductData.hasOwnProperty(product_id)) {
1440                    if (window.pysWooProductData[product_id].hasOwnProperty('facebook')) {
1441
1442                        this.fireEvent(options.woo.affiliateEventName, {
1443                            params: Utils.copyProperties(window.pysWooProductData[product_id]['facebook'], {})
1444                        });
1445
1446                    }
1447                }
1448
1449            },
1450
1451            onWooPayPalEvent: function () {
1452
1453                window.pysWooPayPalData = window.pysWooPayPalData || [];
1454
1455                if (window.pysWooPayPalData.hasOwnProperty('facebook')) {
1456                    this.fireEvent(options.woo.paypalEventName, {
1457                        params: Utils.copyProperties(window.pysWooPayPalData['facebook'], options.facebook.contentParam
1457s)
1458                    });
1459                }
1460
1461            },
1462
1463            onEddAddToCartOnButtonEvent: function (download_id, price_index, qty) {
1464
1465                if (window.pysEddProductData.hasOwnProperty(download_id)) {
1466
1467                    var index;
1468
1469                    if (price_index) {
1470                        index = download_id + '_' + price_index;
1471                    } else {
1472                        index = download_id;
1473                    }
1474
1475                    if (window.pysEddProductData[download_id].hasOwnProperty(index)) {
1476                        if (window.pysEddProductData[download_id][index].hasOwnProperty('facebook')) {
1477
1478                            var params = Utils.copyProperties(window.pysEddProductData[download_id][index]['facebook'], {});
1479
1480                            // maybe customize value option
1481                            if (options.edd.addToCartOnButtonValueEnabled && options.edd.addToCartOnButtonValueOption !== 'global') {
1482                                params.value = params.value * qty;
1483                            }
1484
1485                            // update contents qty param
1486                            var contents = JSON.parse(params.contents);
1487                            contents[0].quantity = qty;
1488                            params.contents = JSON.stringify(contents);
1489
1490                            this.fireEvent('AddToCart', {
1491                                params: params
1492                            });
1493
1494                        }
1495                    }
1496
1497                }
1498
1499            },
1500
1501            onEddRemoveFromCartEvent: function (item) {
1502
1503                if (item.hasOwnProperty('facebook')) {
1504
1505                    this.fireEvent('RemoveFromCart', {
1506                        params: Utils.copyProperties(item['facebook'], {})
1507                    });
1508
1509                }
1510
1511            }
1512
1513        };
1514
1515    }(options);
1516
1517    var Analytics = function (options) {
1518
1519        var initialized = false;
1520
1521        /**
1522         * Fires event
1523         *
1524         * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/sending-data
1525         * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/events
1526         * @link: https://developers.google.com/gtagjs/reference/event
1527         * @link: https://developers.google.com/gtagjs/reference/parameter
1528         *
1529         * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/custom-dims-mets
1530         *
1531         * @param name
1532         * @param data
1533         */
1534        function fireEvent(name, data) {
1535
1536            var eventParams = Utils.copyProperties(data, {});
1537            var requestParams = Utils.getRequestParams();
1538
1539            Utils.copyProperties(requestParams, eventParams);
1540
1541            var _fireEvent = function (tracking_id) {
1542
1543                var params = Utils.copyProperties(eventParams, {send_to: tracking_id});
1544
1545                if (options.debug) {
1546                    console.log('[Google Analytics #' + tracking_id + '] ' + name, params);
1547                }
1548
1549                gtag('event', name, params);
1550
1551            };
1552
1553            options.ga.trackingIds.forEach(function (tracking_id) {
1554                _fireEvent(tracking_id);
1555            });
1556
1557        }
1558
1559        function normalizeEventName(eventName) {
1560
1561            var matches = {
1562                ViewContent: 'view_item',
1563                AddToCart: 'add_to_cart',
1564                AddToWishList: 'add_to_wishlist',
1565                InitiateCheckout: 'begin_checkout',
1566                Purchase: 'purchase',
1567                Lead: 'generate_lead',
1568                CompleteRegistration: 'sign_up',
1569                AddPaymentInfo: 'set_checkout_option'
1570            };
1571
1572            return matches.hasOwnProperty(eventName) ? matches[eventName] : eventName;
1573
1574        }
1575
1576        /**
1577         * Public API
1578         */
1579        return {
1580
1581            isEnabled: function () {
1582                return options.hasOwnProperty('ga');
1583            },
1584
1585            disable: function () {
1586                initialized = false;
1587            },
1588
1589            loadPixel: function () {
1590
1591                if (initialized || !this.isEnabled() || !Utils.consentGiven('analytics')) {
1592                    return;
1593                }
1594
1595                Utils.loadGoogleTag(options.ga.trackingIds[0]);
1596
1597                var cd = {
1598                    'dimension1': 'event_hour',
1599                    'dimension2': 'event_day',
1600                    'dimension3': 'event_month'
1601                };
1602
1603                // configure Dynamic Remarketing CDs
1604                if (options.ga.retargetingLogic === 'ecomm') {
1605                    cd.dimension4 = 'ecomm_prodid';
1606                    cd.dimension5 = 'ecomm_pagetype';
1607                    cd.dimension6 = 'ecomm_totalvalue';
1608                } else {
1609                    cd.dimension4 = 'dynx_itemid';
1610                    cd.dimension5 = 'dynx_pagetype';
1611                    cd.dimension6 = 'dynx_totalvalue';
1612                }
1613
1614                var config = {
1615                    'link_attribution': options.ga.enhanceLinkAttr,
1616                    'anonymize_ip': options.ga.anonimizeIP,
1617                    'custom_map': cd
1618                };
1619
1620                // Google Optimize
1621                if (options.ga.optimizeEnabled) {
1622                    config.optimize_id = options.ga.optimizeId;
1623                }
1624
1625                // Cross-Domain tracking
1626                if (options.ga.crossDomainEnabled) {
1627                    config.linker = {
1628                        accept_incoming: options.ga.crossDomainAcceptIncoming,
1629                        domains: options.ga.crossDomainDomains
1630                    };
1631                }
1632
1633                // configure tracking ids
1634                options.ga.trackingIds.forEach(function (trackingId) {
1635                    gtag('config', trackingId, config);
1636                });
1637
1638                initialized = true;
1639
1640                Utils.fireStaticEvents('ga');
1641
1642            },
1643
1644            fireEvent: function (name, data) {
1645
1646                if (!initialized || !this.isEnabled()) {
1647                    return false;
1648                }
1649
1650                data.delay = data.delay || 0;
1651                data.params = data.params || {};
1652
1653                if (data.delay === 0) {
1654
1655                    fireEvent(name, data.params);
1656
1657                } else {
1658
1659                    setTimeout(function (name, params) {
1660                        fireEvent(name, params);
1661                    }, data.delay * 1000, name, data.params);
1662
1663                }
1664
1665                return true;
1666
1667            },
1668
1669            onAdSenseEvent: function () {
1670                // not supported
1671            },
1672
1673            onClickEvent: function (action, params) {
1674
1675                if (initialized && this.isEnabled() && options.ga.clickEventEnabled) {
1676
1677                    this.fireEvent(action, {
1678                        params: {
1679                            event_category: 'ClickEvent',
1680                            event_label: params.tag_text,
1681                            non_interaction: options.ga.clickEventNonInteractive
1682                        }
1683                    });
1684
1685                }
1686
1687            },
1688
1689            onWatchVideo: function (params) {
1690
1691                if (initialized && this.isEnabled() && options.ga.watchVideoEnabled) {
1692
1693                    this.fireEvent(params.event_trigger, {
1694                        params: {
1695                            event_category: 'WatchVideo',
1696                            event_label: params.video_title,
1697                            non_interaction: options.ga.watchVideoEventNonInteractive
1698                        }
1699                    });
1700
1701                }
1702
1703            },
1704
1705            onCommentEvent: function () {
1706
1707                if (initialized && this.isEnabled() && options.ga.commentEventEnabled) {
1708
1709                    this.fireEvent(window.location.href, {
1710                        params: {
1711                            event_category: 'Comment',
1712                            event_label: $(document).find('title').text(),
1713                            non_interaction: options.ga.commentEventNonInteractive
1714                        }
1715                    });
1716
1717                }
1718
1719            },
1720
1721            onFormEvent: function (params) {
1722
1723                if (initialized && this.isEnabled() && options.ga.formEventEnabled) {
1724
1725                    this.fireEvent(window.location.href, {
1726                        params: {
1727                            event_category: 'Form',
1728                            event_label: params.form_class,
1729                            non_interaction: options.ga.formEventNonInteractive
1730                        }
1731                    });
1732
1733                }
1734
1735            },
1736
1737            onDownloadEvent: function (params) {
1738
1739                if (initialized && this.isEnabled() && options.ga.downloadEnabled) {
1740
1741                    this.fireEvent(params.download_url, {
1742                        params: {
1743                            event_category: 'Download',
1744                            event_label: params.download_name,
1745                            non_interaction: options.ga.downloadEventNonInteractive
1746                        }
1747                    });
1748
1749                }
1750
1751            },
1752
1753            onWooAddToCartOnButtonEvent: function (product_id) {
1754
1755                if (window.pysWooProductData.hasOwnProperty(product_id)) {
1756                    if (window.pysWooProductData[product_id].hasOwnProperty('ga')) {
1757
1758                        this.fireEvent('add_to_cart', {
1759                            params: window.pysWooProductData[product_id]['ga']
1760                        });
1761
1762                    }
1763                }
1764
1765            },
1766
1767            onWooAddToCartOnSingleEvent: function (product_id, qty, is_variable, is_external, $form) {
1768
1769                window.pysWooProductData = window.pysWooProductData || [];
1770
1771                if (is_variable) {
1772                    product_id = parseInt($form.find('input[name="variation_id"]').val());
1773                }
1774
1775                if (window.pysWooProductData.hasOwnProperty(product_id)) {
1776                    if (window.pysWooProductData[product_id].hasOwnProperty('ga')) {
1777
1778                        var params = Utils.copyProperties(window.pysWooProductData[product_id]['ga'], {});
1779
1780                        // maybe customize value option
1781                        if (options.woo.addToCartOnButtonValueEnabled && options.woo.addToCartOnButtonValueOption !== 'global') {
1782                            params.items[0].price = params.items[0].price * qty;
1783                        }
1784
1785                        // update items qty param
1786                        params.items[0].quantity = qty;
1787
1788                        var eventName = is_external ? options.woo.affiliateEventName : 'add_to_cart';
1789                        eventName = normalizeEventName(eventName);
1790
1791                        this.fireEvent(eventName, {
1792                            params: params
1793                        });
1794
1795                    }
1796                }
1797
1798            },
1799
1800            onWooRemoveFromCartEvent: function (cart_item_hash) {
1801
1802                window.pysWooRemoveFromCartData = window.pysWooRemoveFromCartData || [];
1803
1804                if (window.pysWooRemoveFromCartData[cart_item_hash].hasOwnProperty('ga')) {
1805
1806                    this.fireEvent('remove_from_cart', {
1807                        params: Utils.copyProperties(window.pysWooRemoveFromCartData[cart_item_hash]['ga'], {})
1808                    });
1809
1810                }
1811
1812            },
1813
1814            onWooAffiliateEvent: function (product_id) {
1815
1816                if (window.pysWooProductData.hasOwnProperty(product_id)) {
1817                    if (window.pysWooProductData[product_id].hasOwnProperty('ga')) {
1818
1819                        var eventName = normalizeEventName(options.woo.affiliateEventName);
1820
1821                        this.fireEvent(eventName, {
1822                            params: window.pysWooProductData[product_id]['ga']
1823                        });
1824
1825                    }
1826                }
1827
1828            },
1829
1830            onWooPayPalEvent: function () {
1831
1832                eventName = normalizeEventName(options.woo.paypalEventName);
1833
1834                window.pysWooPayPalData = window.pysWooPayPalData || [];
1835
1836                if (window.pysWooPayPalData.hasOwnProperty('ga')) {
1837                    this.fireEvent(eventName, {
1838                        params: Utils.copyProperties(window.pysWooPayPalData['ga'], {})
1839                    });
1840                }
1841
1842            },
1843
1844            onEddAddToCartOnButtonEvent: function (download_id, price_index, qty) {
1845
1846                if (window.pysEddProductData.hasOwnProperty(download_id)) {
1847
1848                    var index;
1849
1850                    if (price_index) {
1851                        index = download_id + '_' + price_index;
1852                    } else {
1853                        index = download_id;
1854                    }
1855
1856                    if (window.pysEddProductData[download_id].hasOwnProperty(index)) {
1857                        if (window.pysEddProductData[download_id][index].hasOwnProperty('ga')) {
1858
1859                            var params = Utils.copyProperties(window.pysEddProductData[download_id][index]['ga'], {});
1860
1861                            // update items qty param
1862                            params.items[0].quantity = qty;
1863
1864                            this.fireEvent('add_to_cart', {
1865                                params: params
1866                            });
1867
1868                        }
1869                    }
1870
1871                }
1872
1873            },
1874
1875            onEddRemoveFromCartEvent: function (item) {
1876
1877                if (item.hasOwnProperty('ga')) {
1878
1879                    this.fireEvent('remove_from_cart', {
1880                        params: Utils.copyProperties(item['ga'], {})
1881                    });
1882
1883                }
1884
1885            }
1886
1887        };
1888
1889    }(options);
1890
1891    var GAds = function (options) {
1892
1893        var initialized = false;
1894
1895        /**
1896         * Fires event
1897         *
1898         * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/sending-data
1899         * @link: https://developers.google.com/analytics/devguides/collection/gtagjs/events
1900         * @link: https://developers.google.com/gtagjs/reference/event
1901         * @link: https://developers.google.com/gtagjs/reference/parameter
1902         */
1903        function fireEvent(name, data, ids) {
1904
1905            var _fireEvent = function (conversion_id) {
1906
1907                params = Utils.copyProperties(data, {send_to: conversion_id});
1908
1909                if (options.debug) {
1910                    console.log('[Google Ads #' + conversion_id + '] ' + n
1910ame, params);
1911                }
1912
1913                gtag('event', name, params);
1914
1915            };
1916
1917            if (ids.length) {
1918
1919                ids.forEach(function (conversion_id) {
1920                    _fireEvent(conversion_id);
1921                });
1922
1923            } else {
1924
1925                options.google_ads.conversion_ids.forEach(function (conversion_id) {
1926                    _fireEvent(conversion_id);
1927                });
1928
1929            }
1930
1931        }
1932
1933        function normalizeEventName(eventName) {
1934
1935            var matches = {
1936                ViewContent: 'view_item',
1937                AddToCart: 'add_to_cart',
1938                AddToWishList: 'add_to_wishlist',
1939                InitiateCheckout: 'begin_checkout',
1940                Purchase: 'purchase',
1941                Lead: 'generate_lead',
1942                CompleteRegistration: 'sign_up',
1943                AddPaymentInfo: 'set_checkout_option'
1944            };
1945
1946            return matches.hasOwnProperty(eventName) ? matches[eventName] : eventName;
1947
1948        }
1949
1950        /**
1951         * Public API
1952         */
1953        return {
1954
1955            isEnabled: function () {
1956                return options.hasOwnProperty('google_ads');
1957            },
1958
1959            disable: function () {
1960                initialized = false;
1961            },
1962
1963            loadPixel: function () {
1964
1965                if (initialized || !this.isEnabled() || !Utils.consentGiven('google_ads')) {
1966                    return;
1967                }
1968
1969                Utils.loadGoogleTag(options.google_ads.conversion_ids[0]);
1970
1971                // configure conversion ids
1972                options.google_ads.conversion_ids.forEach(function (conversion_id) {
1973                    gtag('config', conversion_id);
1974                });
1975
1976                initialized = true;
1977
1978                Utils.fireStaticEvents('google_ads');
1979
1980            },
1981
1982            fireEvent: function (name, data) {
1983
1984                if (!initialized || !this.isEnabled()) {
1985                    return false;
1986                }
1987
1988                data.delay = data.delay || 0;
1989                data.params = data.params || {};
1990                data.ids = data.ids || [];
1991
1992                if (data.delay === 0) {
1993
1994                    fireEvent(name, data.params, data.ids);
1995
1996                } else {
1997
1998                    setTimeout(function (name, params, ids) {
1999                        fireEvent(name, params, ids);
2000                    }, data.delay * 1000, name, data.params, data.ids);
2001
2002                }
2003
2004                return true;
2005
2006            },
2007
2008            onAdSenseEvent: function () {
2009                // not supported
2010            },
2011
2012            onClickEvent: function (action, params) {
2013
2014                if (initialized && this.isEnabled() && options.google_ads.clickEventEnabled) {
2015
2016                    this.fireEvent(action, {
2017                        params: {
2018                            event_category: 'ClickEvent',
2019                            event_label: params.tag_text
2020                        }
2021                    });
2022
2023                }
2024
2025            },
2026
2027            onWatchVideo: function (params) {
2028
2029                if (initialized && this.isEnabled() && options.google_ads.watchVideoEnabled) {
2030
2031                    this.fireEvent(params.event_trigger, {
2032                        params: {
2033                            event_category: 'WatchVideo',
2034                            event_label: params.video_title
2035                        }
2036                    });
2037
2038                }
2039
2040            },
2041
2042            onCommentEvent: function () {
2043
2044                if (initialized && this.isEnabled() && options.google_ads.commentEventEnabled) {
2045
2046                    this.fireEvent(window.location.href, {
2047                        params: {
2048                            event_category: 'Comment',
2049                            event_label: $(document).find('title').text()
2050                        }
2051                    });
2052
2053                }
2054
2055            },
2056
2057            onFormEvent: function (params) {
2058
2059                if (initialized && this.isEnabled() && options.google_ads.formEventEnabled) {
2060
2061                    this.fireEvent(window.location.href, {
2062                        params: {
2063                            event_category: 'Form',
2064                            event_label: params.form_class
2065                        }
2066                    });
2067
2068                }
2069
2070            },
2071
2072            onDownloadEvent: function (params) {
2073
2074                if (initialized && this.isEnabled() && options.google_ads.downloadEnabled) {
2075
2076                    this.fireEvent(params.download_url, {
2077                        params: {
2078                            event_category: 'Download',
2079                            event_label: params.download_name
2080                        }
2081                    });
2082
2083                }
2084
2085            },
2086
2087            onWooAddToCartOnButtonEvent: function (product_id) {
2088
2089                if (window.pysWooProductData.hasOwnProperty(product_id)) {
2090                    if (window.pysWooProductData[product_id].hasOwnProperty('google_ads')) {
2091
2092                        this.fireEvent('add_to_cart', {
2093                            params: window.pysWooProductData[product_id]['google_ads']
2094                        });
2095
2096                    }
2097                }
2098
2099            },
2100
2101            onWooAddToCartOnSingleEvent: function (product_id, qty, is_variable, is_external, $form) {
2102
2103                window.pysWooProductData = window.pysWooProductData || [];
2104
2105                if (is_variable) {
2106                    product_id = parseInt($form.find('input[name="variation_id"]').val());
2107                }
2108
2109                if (window.pysWooProductData.hasOwnProperty(product_id)) {
2110                    if (window.pysWooProductData[product_id].hasOwnProperty('google_ads')) {
2111
2112                        var params = Utils.copyProperties(window.pysWooProductData[product_id]['google_ads'], {});
2113
2114                        // maybe customize value option
2115                        if (options.woo.addToCartOnButtonValueEnabled && options.woo.addToCartOnButtonValueOption !== 'global') {
2116                            params.items[0].price = params.items[0].price * qty;
2117                        }
2118
2119                        // update items qty param
2120                        params.items[0].quantity = qty;
2121
2122                        var eventName = is_external ? options.woo.affiliateEventName : 'add_to_cart';
2123                        eventName = normalizeEventName(eventName);
2124
2125                        this.fireEvent(eventName, {
2126                            params: params
2127                        });
2128
2129                    }
2130                }
2131
2132            },
2133
2134            onWooRemoveFromCartEvent: function (cart_item_hash) {
2135
2136                window.pysWooRemoveFromCartData = window.pysWooRemoveFromCartData || [];
2137
2138                if (window.pysWooRemoveFromCartData[cart_item_hash].hasOwnProperty('google_ads')) {
2139
2140                    this.fireEvent('remove_from_cart', {
2141                        params: Utils.copyProperties(window.pysWooRemoveFromCartData[cart_item_hash]['google_ads'], {})
2142                    });
2143
2144                }
2145
2146            },
2147
2148            onWooAffiliateEvent: function (product_id) {
2149
2150                if (window.pysWooProductData.hasOwnProperty(product_id)) {
2151                    if (window.pysWooProductData[product_id].hasOwnProperty('google_ads')) {
2152
2153                        var eventName = normalizeEventName(options.woo.affiliateEventName);
2154
2155                        this.fireEvent(eventName, {
2156                            params: window.pysWooProductData[product_id]['google_ads']
2157                        });
2158
2159                    }
2160                }
2161
2162            },
2163
2164            onWooPayPalEvent: function () {
2165
2166                eventName = normalizeEventName(options.woo.paypalEventName);
2167
2168                window.pysWooPayPalData = window.pysWooPayPalData || [];
2169
2170                if (window.pysWooPayPalData.hasOwnProperty('google_ads')) {
2171                    this.fireEvent(eventName, {
2172                        params: Utils.copyProperties(window.pysWooPayPalData['google_ads'], {})
2173                    });
2174                }
2175
2176            },
2177
2178            onEddAddToCartOnButtonEvent: function (download_id, price_index, qty) {
2179
2180                if (window.pysEddProductData.hasOwnProperty(download_id)) {
2181
2182                    var index;
2183
2184                    if (price_index) {
2185                        index = download_id + '_' + price_index;
2186                    } else {
2187                        index = download_id;
2188                    }
2189
2190                    if (window.pysEddProductData[download_id].hasOwnProperty(index)) {
2191                        if (window.pysEddProductData[download_id][index].hasOwnProperty('google_ads')) {
2192
2193                            var params = Utils.copyProperties(window.pysEddProductData[download_id][index]['google_ads'], {});
2194
2195                            // update items qty param
2196                            params.items[0].quantity = qty;
2197
2198                            this.fireEvent('add_to_cart', {
2199                                params: params
2200                            });
2201
2202                        }
2203                    }
2204
2205                }
2206
2207            },
2208
2209            onEddRemoveFromCartEvent: function (item) {
2210
2211                if (item.hasOwnProperty('google_ads')) {
2212
2213                    this.fireEvent('remove_from_cart', {
2214                        params: Utils.copyProperties(item['google_ads'], {})
2215                    });
2216
2217                }
2218
2219            }
2220
2221        };
2222
2223    }(options);
2224
2225    window.pys = window.pys || {};
2226    window.pys.Facebook = Facebook;
2227    window.pys.Analytics = Analytics;
2228    window.pys.GAds = GAds;
2229    window.pys.Utils = Utils;
2230
2231    $(document).ready(function () {
2232
2233        var Pinterest = Utils.setupPinterestObject();
2234
2235        Utils.manageCookies();
2236        Utils.initializeRequestParams();
2237        Utils.setupGdprCallbacks();
2238
2239        // setup Click Event
2240        if (options.clickEventEnabled) {
2241
2242            $(document).onFirst('click', 'a, button, input[type="button"], input[type="submit"]', function () {
2243
2244                var $elem = $(this),
2245                    params = {},
2246                    ga_action = 'Button';
2247
2248                if ($elem.hasClass('pys_block')) {
2249                    return; // avoiding fake double clicks from Affiliate event
2250                }
2251
2252                if ($elem.is('a')) {
2253                    params.tag_type = 'a';
2254                    params.tag_text = $elem.text();
2255                    ga_action = $elem.attr('href');
2256                } else if ($elem.is('button')) {
2257                    params.tag_type = 'button';
2258                    params.tag_text = $elem.text();
2259                } else if ($elem.is('input[type="button"]')) {
2260                    params.tag_type = 'input.button';
2261                    params.tag_text = $elem.val();
2262                } else if ($elem.is('input[type="submit"]')) {
2263                    params.tag_type = 'input.submit';
2264                    params.tag_text = $elem.val();
2265                } else {
2266                    return;
2267                }
2268
2269                params.tag_text = Utils.filterEmails(params.tag_text);
2270
2271                Facebook.onClickEvent(params);
2272                Analytics.onClickEvent(ga_action, params);
2273                GAds.onClickEvent(ga_action, params);
2274                Pinterest.onClickEvent(params);
2275
2276            });
2277
2278        }
2279
2280        // setup AdSense Event
2281        if (options.adSenseEventEnabled) {
2282
2283            var isOverGoogleAd = false;
2284
2285            $(document)
2286                .on('mouseover', 'ins > ins > iframe', function () {
2287                    isOverGoogleAd = true;
2288                })
2289                .on('mouseout', 'iframe', function () {
2290                    isOverGoogleAd = false;
2291                });
2292
2293            $(window)
2294                .blur(function () {
2295                    if (isOverGoogleAd) {
2296                        Facebook.onAdSenseEvent();
2297                        Analytics.onAdSenseEvent();
2298                        GAds.onAdSenseEvent();
2299                        Pinterest.onAdSenseEvent();
2300                    }
2301                })
2302                .focus();
2303
2304        }
2305
2306        // setup Dynamic events
2307        $.each(options.dynamicEventsTriggers, function (triggerType, events) {
2308
2309            $.each(events, function (eventId, triggers) {
2310
2311                switch (triggerType) {
2312                    case 'url_click':
2313                        //@see: Utils.setupURLClickEvents()
2314                        break;
2315
2316                    case 'css_click':
2317                        Utils.setupCSSClickEvents(eventId, triggers);
2318                        break;
2319
2320                    case 'css_mouseover':
2321                        Utils.setupMouseOverClickEvents(eventId, triggers);
2322                        break;
2323
2324                    case 'scroll_pos':
2325                        Utils.setupScrollPosEvents(eventId, triggers);
2326                        break;
2327                }
2328
2329            });
2330
2331        });
2332
2333        // setup WooCommerce events
2334        if (options.woo.enabled) {
2335
2336            // WooCommerce AddToCart
2337            if (options.woo.addToCartOnButtonEnabled) {
2338
2339                // Loop, any kind of "simple" product, except external
2340                $('.add_to_cart_button:not(.product_type_variable)').click(function (e) {
2341
2342                    var product_id = $(this).data('product_id');
2343
2344                    if (typeof product_id !== 'undefined') {
2345                        Facebook.onWooAddToCartOnButtonEvent(product_id);
2346                        Analytics.onWooAddToCartOnButtonEvent(product_id);
2347                        GAds.onWooAddToCartOnButtonEvent(product_id);
2348                        Pinterest.onWooAddToCartOnButtonEvent(product_id);
2349                    }
2350
2351                });
2352
2353                // Single Product
2354                $('.single_add_to_cart_button').click(function (e) {
2355
2356                    var $button = $(this);
2357
2358                    if ($button.hasClass('disabled')) {
2359                        return;
2360                    }
2361
2362                    var $form = $button.closest('form');
2363
2364                    var is_variable = false;
2365                    var is_external = false;
2366
2367                    if ($form.length === 0) {
2368                        is_external = true;
2369                    } else if ($form.hasClass('variations_form')) {
2370                        is_variable = true;
2371                    }
2372
2373                    var product_id;
2374                    var qty;
2375
2376                    if (is_variable) {
2377                        product_id = parseInt($form.find('*[name="add-to-cart"]').val());
2378                        qty = parseInt($form.find('input[name="quantity"]').val());
2379                    } else if (is_external) {
2380                        product_id = options.woo.singleProductId;
2381                        qty = 1;
2382                    } else {
2383                        product_id = parseInt($form.find('*[name="add-to-cart"]').val());
2384                        qty = parseInt($form.find('input[name="quantity"]').val());
2385                    }
2386
2387                    Facebook.onWooAddToCartOnSingleEvent(product_id, qty, is_variable, is_external, $form);
2388                    Analytics.onWooAddToCartOnSingleEvent(product_id, qty, is_variable, is_external, $form);
2389                    GAds.onWooAddToCartOnSingleEvent(product_id, qty, is_variable, is_external, $form);
2390                    Pinterest.onWooAddToCartOnSingleEvent(product_id, qty, is_variable, is_external, $form);
2391
2392                });
2393
2394            }
2395
2396            // WooCommerce Affiliate
2397            if (options.woo.affiliateEnabled) {
2398
2399                // Loop, external
2400                $('.product_type_external').click(function (e) {
2401
2402                    var product_id = $(this).data('product_id');
2403
2404                    if (typeof product_id !== 'undefined') {
2405                        Facebook.onWooAffiliateEvent(product_id);
2406                        Analytics.onWooAffiliateEvent(product_id);
2407                        GAds.onWooAffiliateEvent(product_id);
2408                        Pinterest.onWooAffiliateEvent(product_id);
2409                    }
2410
2411                });
2412
2413            }
2414
2415            // WooCommerce RemoveFromCart
2416            if (options.woo.removeFromCartEnabled) {
2417
2418                $('body').on('click', options.woo.removeFromCartSelector, function (e) {
2419
2420                    var $a = $(e.currentTarget),
2421                        href = $a.attr('href');
2422
2423                    // extract cart item hash from remove button URL
2424                    var regex = new RegExp("[\\?&]remove_item=([^&#]*)"),
2425                        results = regex.exec(href);
2426
2427                    if (results !== null) {
2428
2429                        var item_hash = results[1];
2430                        window.pysWooRemoveFromCartData = window.pysWooRemoveFromCartData || [];
2431
2432                        if (window.pysWooRemoveFromCartData.hasOwnProperty(item_hash)) {
2433                            Facebook.onWooRemoveFromCartEvent(item_hash);
2434                            Analytics.onWooRemoveFromCartEvent(item_hash);
2435                            GAds.onWooRemoveFromCartEvent(item_hash);
2436                            Pinterest.onWooRemoveFromCartEvent(item_hash);
2437                        }
2438
2439                    }
2440
2441                });
2442
2443            }
2444
2445            // WooCommerce PayPal
2446            if (options.woo.payPalEnabled) {
2447
2448                // Non-default binding used to avoid situations when some code in external js
2449                // stopping events propagation, eg. returns false, and our handler will never called
2450                $(document).onFirst('submit click', '#place_order', function (e) {
2451
2452                    var method = $('form[name="checkout"] input[name="payment_method"]:checked').val();
2453
2454                    if (method !== 'paypal') {
2455                        return;
2456                    }
2457
2458                    Facebook.onWooPayPalEvent();
2459                    Analytics.onWooPayPalEvent();
2460                    GAds.onWooPayPalEvent();
2461                    Pinterest.onWooPayPalEvent();
2462
2463                });
2464
2465            }
2466
2467        }
2468
2469        // setup EDD events
2470        if (options.edd.enabled) {
2471
2472            // EDD AddToCart
2473            if (options.edd.addToCartOnButtonEnabled) {
2474
2475                $('form.edd_download_purchase_form .edd-add-to-cart').click(function (e) {
2476
2477                    var $button = $(this);
2478                    var $form = $button.closest('form');
2479                    var variable_price = $button.data('variablePrice'); // yes/no
2480                    var price_mode = $button.data('priceMode'); // single/multi
2481                    var ids = [];
2482                    var quantities = [];
2483                    var qty;
2484                    var id;
2485
2486                    if (variable_price === 'yes' && price_mode === 'multi') {
2487
2488                        id = $form.find('input[name="download_id"]').val();
2489
2490                        // get selected variants
2491                        $.each($form.find('input[name="edd_options[price_id][]"]:checked'), function (i, el) {
2492                            ids.push(id + '_' + $(el).val());
2493                        });
2494
2495                        // get qty for selected variants
2496                        $.each(ids, function (i, variant_id) {
2497
2498                            var variant_index = variant_id.split('_', 2);
2499                            qty = $form.find('input[name="edd_download_quantity_' + variant_index[1] + '"]').val();
2500
2501                            if (typeof qty !== 'undefined') {
2502                                quantities.push(qty);
2503                            } else {
2504                                quantities.push(1);
2505                            }
2506
2507                        });
2508
2509                    } else if (variable_price === 'yes' && price_mode === 'single') {
2510
2511                        id = $form.find('input[name="download_id"]').val();
2512                        ids.push(id + '_' + $form.find('input[name="edd_options[price_id][]"]:checked').val());
2513
2514                        qty = $form.find('input[name="edd_download_quantity"]').val();
2515
2516                        if (typeof qty !== 'undefined') {
2517                            quantities.push(qty);
2518                        } else {
2519                            quantities.push(1);
2520                        }
2521
2522                    } else {
2523
2524                        ids.push($button.data('downloadId'));
2525
2526                        qty = $form.find('input[name="edd_download_quantity"]').val();
2527
2528                        if (typeof qty !== 'undefined') {
2529                            quantities.push(qty);
2530                        } else {
2531                            quantities.push(1);
2532                        }
2533
2534
2535                    }
2536
2537                    // fire event for each download/variant
2538                    $.each(ids, function (i, download_id) {
2539
2540                        var q = parseInt(quantities[i]);
2541                        var variant_index = download_id.toString().split('_', 2);
2542                        var price_index;
2543
2544                        if (variant_index.length === 2) {
2545                            download_id = variant_index[0];
2546                            price_index = variant_index[1];
2547                        }
2548
2549                        Facebook.onEddAddToCartOnButtonEvent(download_id, price_index, q);
2550                        Analytics.onEddAddToCartOnButtonEvent(download_id, price_index, q);
2551                        GAds.onEddAddToCartOnButtonEvent(download_id, price_index, q);
2552                        Pinterest.onEddAddToCartOnButtonEvent(download_id, price_index, q);
2553
2554                    });
2555
2556                });
2557
2558            }
2559
2560            // EDD RemoveFromCart
2561            if (options.edd.removeFromCartEnabled) {
2562
2563                $('form#edd_checkout_cart_form .edd_cart_remove_item_btn').click(function (e) {
2564
2565                    var href = $(this).attr('href');
2566                    var key = href.substring(href.indexOf('=') + 1).charAt(0);
2567
2568                    window.pysEddRemoveFromCartData = window.pysEddRemoveFromCartData || [];
2569
2570                    if (window.pysEddRemoveFromCartData[key]) {
2571
2572                        var item = window.pysEddRemoveFromCartData[key];
2573
2574                        Facebook.onEddRemoveFromCartEvent(item);
2575                        Analytics.onEddRemoveFromCartEvent(item);
2576                        GAds.onEddRemoveFromCartEvent(item);
2577                        Pinterest.onEddRemoveFromCartEvent(item);
2578
2579                    }
2580
2581                });
2582
2583            }
2584
2585        }
2586
2587        Utils.setupURLClickEvents();
2588
2589        // setup Comment Event
2590        if (options.commentEventEnabled) {
2591
2592            $('form.comment-form').submit(function () {
2593
2594                Facebook.onCommentEvent();
2595                Analytics.onCommentEvent();
2596                GAds.onCommentEvent();
2597                Pinterest.onCommentEvent();
2598
2599            });
2600
2601        }
2602
2603        // setup Form Event
2604        if (options.formEventEnabled) {
2605
2606            $(document).onFirst('submit', 'form', function () {
2607
2608                var $form = $(this);
2609
2610                // exclude WP forms
2611                if ($form.hasClass('comment-form') || $form.hasClass('search-form') || $form.attr('id') === 'adminbarsearch' ) {
2612                    return;
2613                }
2614
2615                // exclude Woo forms
2616                if ($form.hasClass('woocommerce-product-search') || $form.hasClass('cart') || $form.hasClass('woocommerce-cart-form')
2617                    || $form.hasClass('woocommerce-shipping-calculator') || $form.hasClass('checkout') || $form.hasClass('checkout_coupon')) {
2618                    return;
2619                }
2620
2621                // exclude EDD forms
2622                if ($form.hasClass('edd_form') || $form.hasClass('edd_download_purchase_form')) {
2623                    return;
2624                }
2625
2626                var params = {
2627                    form_id: $form.attr('id'),
2628                    form_class: $form.attr('class')
2629                };
2630
2631                Facebook.onFormEvent(params);
2632                Analytics.onFormEvent(params);
2633                GAds.onFormEvent(params);
2634                Pinterest.onFormEvent(params);
2635
2636            });
2637
2638            // Ninja Forms
2639            $(document).onFirst('nfFormSubmitResponse', function (e, data) {
2640
2641                var params = {
2642                    form_id: data.response.data.form_id,
2643                    form_title: data.response.data.settings.title
2644                };
2645
2646                Facebook.onFormEvent(params);
2647                Analytics.onFormEvent(params);
2648                GAds.onFormEvent(params);
2649                Pinterest.onFormEvent(params);
2650
2651            });
2652
2653        }
2654
2655        // setup DownloadDocs event
2656        if (options.downloadEventEnabled && options.downloadExtensions.length > 0) {
2657
2658            $('body').click(function (event) {
2659
2660                var el = event.srcElement || event.target;
2661
2662                /* Loop up the DOM tree through parent elements if clicked element is not a link (eg: an image inside a link) */
2663                while (el && (typeof el.tagName === 'undefined' || el.tagName.toLowerCase() !== 'a' || !el.href )) {
2664                    el = el.parentNode;
2665                }
2666
2667                if (el && el.href) {
2668
2669                    var extension = Utils.getLinkExtension(el.href);
2670                    var track_download = false;
2671
2672                    if (extension.length > 0) {
2673
2674                        for (i = 0, len = options.downloadExtensions.length; i < len; ++i) {
2675                            if (options.downloadExtensions[i] === extension) {
2676                                track_download = true;
2677                                break;
2678                            }
2679                        }
2680
2681                    }
2682
2683                    if (track_download) {
2684
2685                        var params = {
2686                            download_url: el.href,
2687                            download_type: extension,
2688                            download_name: Utils.getLinkFilename(el.href)
2689                        };
2690
2691                        Facebook.onDownloadEvent(params);
2692                        Analytics.onDownloadEvent(params);
2693                        GAds.onDownloadEvent(params);
2694                        Pinterest.onDownloadEvent(params);
2695
2696                    }
2697
2698                }
2699
2700            });
2701
2702        }
2703
2704        // load pixel APIs
2705        Utils.loadPixels();
2706
2707    });
2708
2709    // load WatchVideo event APIs
2710    if (options.watchVideoEnabled) {
2711        Utils.initYouTubeAPI();
2712        Utils.initVimeoAPI();
2713    }
2714
2715}(jQuery, pysOptions);

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.