PageSourceSearch

https://www.galls.com/assets/js/marketing-tech/ga4FooterTracking.js?v=1.0.0

js galls.com collected 2026-09-24 19:40:08 UTC 5,593 bytes, 184 lines download raw bytes

1// Send events to GA4
2// ===== Send GA4 Events =====
3
4// Send GA4 event generic call
5function sendGA4Event(eventName, eventParams = {}) {
6    if (!window.dataLayer) {
7      window.dataLayer = [];
8    }
9    window.dataLayer.push({
10      event: eventName,
11      ...eventParams
12    });
13}
14
15// "Remove From Cart" event in sidecart
16function ga4SendRemoveFromCartEvent(sku, deletedProduct) {
17  const ecommerceObj = removeFromMinicartObj(deletedProduct);
18
19  dataLayer.push({ ecommerce: null });
20  dataLayer.push({
21      event: 'remove_from_cart_mini',
22      ecommerce: ecommerceObj
23  });
24}
25
26// "Add To Cart Quickview" event in Sam's dynamic carousels
27function ga4SendSamDynamicCarouselATCEvent(eventName) {
28  dataLayer.push({ ecommerce: null });
29  dataLayer.push({
30      event: eventName || 'view_qv',
31  });
32}
33
34// "View Minicart" event in header
35function ga4SendViewMiniCartEvent(eventName) {
36  dataLayer.push({ ecommerce: null });
37  dataLayer.push({
38      event: eventName || 'view_mini_cart',
39  });
40}
41
42// ===== End Send GA4 Events =====
43
44
45function removeFromMinicartObj(cartItem) {
46  const imageURL = cartItem[0];
47  const description = cartItem[1];
48  const optionsHTML = cartItem[2];
49  const stockMessage = cartItem[3];
50  const vas = cartItem[4];
51  const price = cartItem[5];
52  const extendedPrice = cartItem[6];
53  const cdno = cartItem[7];
54  const quantity = cartItem[8];
55  const subtotal = cartItem[9];
56  const customizationFee = cartItem[10];
57  const itemTotal = cartItem[11];
58  const itemID = cartItem[12];
59  const errorMessage = cartItem[13];
60  const locationID = cartItem[14];
61  const cdnoRepeat = cartItem[15];
62  const itemType = cartItem[16];
63
64  // Options
65  function getProductOptions(optionsHTML) {
66      const tempDiv = document.createElement('div');
67      tempDiv.innerHTML = optionsHTML;
68      const listItems = tempDiv.querySelectorAll('li');
69  
70      return {
71          option1: listItems[0]?.textContent.trim() || '',
72          option2: listItems[1]?.textContent.trim() || '',
73          option3: listItems[2]?.textContent.trim() || ''
74      };
75  }
76  
77  const { option1, option2, option3 } = getProductOptions(optionsHTML);    
78
79  // Price
80  function getPriceValues(priceHTML) {
81      const tempDiv = document.createElement('div');
82      tempDiv.innerHTML = priceHTML;
83  
84      const original = tempDiv.querySelector('.original')?.textContent.replace('$', '').trim() || '';
85      const discount = tempDiv.querySelector('.discount')?.textContent.replace('$', '').trim() || '';
86      const strong = tempDiv.querySelector('strong')?.textContent.replace('$', '').trim() || '';
87  
88      return {
89          originalPrice: original || strong,
90          discountPrice: discount
91      };
92  }
93  
94  const { originalPrice, discountPrice } = getPriceValues(price);
95
96  return {
97      currency: "USD",
98      value: "",
99      items: [
100          {
101              item_id: `${itemID}`,
102              item_name: description.replace(/"/g, '"'),
103              affiliation: "Galls Website",
104              item_variant1: option1,
105              item_variant2: option2,
106              item_variant3: option3,
107              location_id: locationID,
108              price: parseFloat(originalPrice),
109              discountPrice: parseFloat(discountPrice),
110              customizationFee: parseFloat(customizationFee) || '',
111              quantity: parseInt(quantity, 10)
112          }
113      ]
114  };
115}
116
117// "Sponsored Ads View/Click" event for PLP grid banners
118function ga4SendSponsoredAdEvent(adData, eventType = 'view') {
119  const eventName = eventType === 'view' ? 'view' : 'click';
120  
121  const ecommerceObj = {
122    ad_id: adData.ad_id || '',
123    template: adData.template || '',
124    type: adData.type || 'grid_banner',
125    url: adData.url || '',
126    description: adData.description || '',
127    row: adData.rowNum ? String(adData.rowNum) : '',
128    start_date: adData.start_date || '',
129    start_time: adData.start_time || '',
130    target_url: adData.buttonLink || adData.product || '',
131    sponsor: adData.sponsor || ''
132  };
133
134  dataLayer.push({ ecommerce: null });
135  dataLayer.push({
136    event: eventName,
137    ecommerce: ecommerceObj
138  });
139}
140
141/* === Listen for Sponsored Ad Events === */
142document.addEventListener('sponsoredAdView', function(e) {
143  ga4SendSponsoredAdEvent(e.detail, 'view');
144});
145
146document.addEventListener('sponsoredAdClick', function(e) {
147  ga4SendSponsoredAdEvent(e.detail, 'click');
148});
149/* === End Sponsored Ad Events === */
150
151// web-999 stage only
152/* === PDP Promo Bar Events === */
153function ga4SendPromoBarEvent(adData, eventType = 'view') {
154  const eventName = eventType === 'view' ? 'view' : 'click';
155  
156  const ecommerceObj = {
157    ad_id: adData.ad_id || '',
158    template: 'pdp',
159    type: 'promo_bar',
160    url: adData.cta_link || '',
161    description: adData.primary_text || '',
162    start_date: adData.start_date || '',
163    end_date: adData.end_date || '',
164    priority_rank: adData.priority_rank || 0,
165    product_slug: adData.product_slug || '',
166    sponsor_brand: adData.sponsor_brand || '',
167    sponsored: adData.is_sponsored || false
168  };
169
170  dataLayer.push({ ecommerce: null });
171  dataLayer.push({
172    event: eventName,
173    ecommerce: ecommerceObj
174  });
175}
176
177document.addEventListener('promoBarView', function(e) {
178  ga4SendPromoBarEvent(e.detail, 'view');
179});
180
181document.addEventListener('promoBarClick', function(e) {
182  ga4SendPromoBarEvent(e.detail, 'click');
183});
184/* === End PDP Promo Bar Events === */

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.