PageSourceSearch

https://ahmegon.com/catalog/view/theme/journal3/js/ahmegon-ga4-ecommerce.js?v=20260809c

js ahmegon.com collected 2026-09-24 10:15:21 UTC 6,451 bytes, 238 lines download raw bytes

1(function (window, document) {
2  'use strict';
3
4  var ready = false;
5  var pending = [];
6
7  function storageGet(store, key) {
8    try {
9      return store.getItem(key);
10    } catch (e) {
11      return null;
12    }
13  }
14
15  function storageSet(store, key, value) {
16    try {
17      store.setItem(key, value);
18    } catch (e) {
19      // Measurement must never interrupt the shopping flow.
20    }
21  }
22
23  function sendNow(eventName, params, options) {
24    options = options || {};
25    params = params || {};
26
27    if (!eventName || typeof window.gtag !== 'function') {
28      return;
29    }
30
31    if (eventName === 'purchase' && params.transaction_id) {
32      var purchaseKey = 'ahm_ga4_purchase_' + String(params.transaction_id);
33      if (storageGet(window.localStorage, purchaseKey)) {
34        return;
35      }
36      storageSet(window.localStorage, purchaseKey, '1');
37    }
38
39    window.gtag('event', eventName, params);
40
41    if (eventName === 'purchase' && options.ads_send_to) {
42      window.gtag('config', 'AW-11493962788');
43      window.gtag('event', 'conversion', {
44        send_to: options.ads_send_to,
45        value: Number(params.value || 0),
46        currency: params.currency || 'TRY',
47        transaction_id: String(params.transaction_id || '')
48      });
49    }
50
51    window.__AHMEGON_GA4_LAST_EVENT__ = {
52      event: eventName,
53      params: params,
54      sent_at: new Date().toISOString()
55    };
56
57    // Non-sensitive QA marker: makes the last emitted event observable from
58    // automated browser checks without exposing customer or order data.
59    document.documentElement.setAttribute('data-ahm-ga4-last-event', eventName);
60    if (params.transaction_id) {
61      document.documentElement.setAttribute('data-ahm-ga4-last-transaction', String(params.transaction_id));
62    }
63  }
64
65  function send(eventName, params, options) {
66    if (!ready) {
67      pending.push([eventName, params, options]);
68      return;
69    }
70    sendNow(eventName, params, options);
71  }
72
73  function flush() {
74    ready = true;
75    while (pending.length) {
76      var eventData = pending.shift();
77      sendNow(eventData[0], eventData[1], eventData[2]);
78    }
79  }
80
81  function pageEvent() {
82    var config = window.AHMEGON_GA4_PAGE;
83
84    if (!config && window._QuickCheckoutData && window._QuickCheckoutData.ahmegon_ga4) {
85      config = window._QuickCheckoutData.ahmegon_ga4;
86    }
87
88    if (config && config.event && config.params) {
89      send(config.event, config.params, config);
90    }
91  }
92
93  function ecommerceContext() {
94    var config = window.AHMEGON_GA4_PAGE;
95
96    if (!config && window._QuickCheckoutData && window._QuickCheckoutData.ahmegon_ga4) {
97      config = window._QuickCheckoutData.ahmegon_ga4;
98    }
99
100    return config && config.params ? config.params : {};
101  }
102
103  function checkoutContextKey(context) {
104    var items = context.items || [];
105    var itemKey = items.map(function (item) {
106      return String(item.item_id || '') + ':' + String(item.quantity || 1);
107    }).join(',');
108
109    return [
110      String(context.currency || 'TRY'),
111      String(Number(context.value || 0).toFixed(2)),
112      itemKey
113    ].join('|');
114  }
115
116  function sendCheckoutSelection(target) {
117    var eventName = '';
118    var detailName = '';
119    var detailValue = '';
120
121    if (!target || !target.name || !target.checked) {
122      return;
123    }
124
125    if (target.name === 'shipping_method') {
126      eventName = 'add_shipping_info';
127      detailName = 'shipping_tier';
128      detailValue = target.value || '';
129    } else if (target.name === 'payment_method') {
130      eventName = 'add_payment_info';
131      detailName = 'payment_type';
132      detailValue = target.value || '';
133    } else {
134      return;
135    }
136
137    var context = ecommerceContext();
138    var key = 'ahm_ga4_' + eventName + '_' + detailValue + '_' + checkoutContextKey(context);
139
140    if (storageGet(window.sessionStorage, key)) {
141      return;
142    }
143
144    storageSet(window.sessionStorage, key, '1');
145
146    var params = {
147      currency: context.currency || 'TRY',
148      value: Number(context.value || 0),
149      items: context.items || []
150    };
151    params[detailName] = detailValue;
152    send(eventName, params);
153  }
154
155  function sendInitialCheckoutSelections() {
156    var selected = document.querySelectorAll(
157      'input[name="shipping_method"]:checked, input[name="payment_method"]:checked'
158    );
159
160    Array.prototype.forEach.call(selected, sendCheckoutSelection);
161  }
162
163  function checkoutSelections() {
164    document.addEventListener('change', function (event) {
165      var target = event.target;
166
167      window.setTimeout(function () {
168        sendCheckoutSelection(target);
169      }, 650);
170    }, true);
171
172    // Journal selects the first available shipping and payment methods while
173    // rendering the checkout. Those defaults do not emit a native change event,
174    // so record them once after the Vue checkout has finished mounting.
175    window.setTimeout(sendInitialCheckoutSelections, 1200);
176
177    var selectionPolls = 0;
178    var selectionTimer = window.setInterval(function () {
179      selectionPolls += 1;
180      sendInitialCheckoutSelections();
181
182      if (document.querySelector('input[name="shipping_method"]:checked') &&
183          document.querySelector('input[name="payment_method"]:checked')) {
184        window.clearInterval(selectionTimer);
185      } else if (selectionPolls >= 20) {
186        window.clearInterval(selectionTimer);
187      }
188    }, 500);
189  }
190
191  function ajaxEvents() {
192    if (!window.jQuery) {
193      return;
194    }
195
196    window.jQuery(document).ajaxSuccess(function (event, xhr, settings, response) {
197      var url = settings && settings.url ? String(settings.url) : '';
198
199      if (url.indexOf('journal3/checkout') !== -1) {
200        window.setTimeout(sendInitialCheckoutSelections, 800);
201      }
202
203      if (url.indexOf('checkout/cart/add') === -1) {
204        return;
205      }
206
207      var json = response;
208      if (typeof json === 'string') {
209        try {
210          json = JSON.parse(json);
211        } catch (e) {
212          return;
213        }
214      }
215
216      if (json && json.ahmegon_ga4 && json.ahmegon_ga4.params) {
217        send('add_to_cart', json.ahmegon_ga4.params);
218      }
219    });
220  }
221
222  window.AhmegonGA4 = {
223    send: send
224  };
225
226  function initialize() {
227    flush();
228    pageEvent();
229    checkoutSelections();
230    ajaxEvents();
231  }
232
233  if (document.readyState === 'loading') {
234    document.addEventListener('DOMContentLoaded', initialize, { once: true });
235  } else {
236    initialize();
237  }
238})(window, document);

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.