PageSourceSearch

https://www.farmaciarosario.com.br/staticfiles/js/analytics-loader.js

js farmaciarosario.com.br collected 2026-10-09 04:20:07 UTC 25,590 bytes, 648 lines download raw bytes

1(function (w, d) {
2  const C = w.__AN_CFG || {};
3
4  // flags com defaults inteligentes
5  // se tem GTM (Google Tag Manager) os demais são false por default, visto que ele fará o trabalho de disparar eventos.
6  const metaAutoPV = ('metaAutoPageView' in C) ? !!C.metaAutoPageView     : false;  // default = false | GTM != gtag (Google Analytics (GA4))
7  const gaAutoPV     = ('gaAutoPageView'   in C) ? !!C.gaAutoPageView     : false; 
8  //const ttAutoPage   = ('tiktokAutoPage'   in C) ? !!C.tiktokAutoPage     : false; 
9
10  // util
11  function loadScript(src, { async = true, defer = true, id } = {}) {
12    if (id && d.getElementById(id)) return Promise.resolve();
13    return new Promise((resolve, reject) => {
14      const s = d.createElement('script');
15      if (id) s.id = id;
16      s.src = src; s.async = async; s.defer = defer;
17      s.onload = resolve; s.onerror = reject;
18      d.head.appendChild(s);
19    });
20  }
21
22  // Inicializa gtag quando necessário para envio GA4 direto.
23  // Observação: o gtag usa uma fila própria de comandos (array de arguments).
24  function inicializaGtag() {
25    w.dataLayer = w.dataLayer || [];
26    w.gtag = w.gtag || function(){ w.dataLayer.push(arguments); };
27  }
28
29  // -----------------------------
30  // Google Tag Manager (preferir GTM se existir)
31  // -----------------------------
32  if (C.gtm) {
33    (function(w,d,s,l,i){
34      w[l]=w[l]||[]; w[l].push({'gtm.start': new Date().getTime(), event:'gtm.js'});
35      const f=d.getElementsByTagName(s)[0], j=d.createElement(s), dl=l!='dataLayer' ? '&l='+l : '';
36      j.async=true;
36 j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl; f.parentNode.insertBefore(j,f);
37    })(w,d,'script','dataLayer', C.gtm);
38
39    // Com GTM ativo, não inicializa GA4 direto via gtag para evitar conflito/duplicidade.
40  } else if (C.ga4 || C.ga4_retailon) {
41    // se NÃO usar GTM, carrega gtag.js direto para GA4
42    const primaryId = C.ga4 || C.ga4_retailon;
43    loadScript(`https://www.googletagmanager.com/gtag/js?id=${primaryId}`);
44    inicializaGtag();
45    gtag('js', new Date());
46    if (C.ga4) gtag('config', C.ga4, { send_page_view: gaAutoPV }); // default: false
47    if (C.ga4_retailon) gtag('config', C.ga4_retailon, { send_page_view: gaAutoPV }); // default: false
48  }
49
50  // -----------------------------
51  // Meta Pixel
52  // -----------------------------
53  if (C.fb_pixel) {
54    if (!w.fbq) {
55      !function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
56      n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
57      n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
58      t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}
59      (w, d, 'script', 'https://connect.facebook.net/en_US/fbevents.js');
60    }
61    w.__fb_inited_ids = w.__fb_inited_ids || new Set();
62    if (!w.__fb_inited_ids.has(C.fb_pixel)) {
63      trackFbq('init', C.fb_pixel);
64      w.__fb_inited_ids.add(C.fb_pixel);
65    }
66    if (metaAutoPV) trackFbq('track', 'PageView'); // só se flag ligada
67  }
68
69  // -----------------------------
70  // TikTok Pixel
71  // -----------------------------
72  // if (C.tiktok) {
73  //   !(function (w, d, t) {
74  //     w.TiktokAnalyticsObject = t;
75  //     var ttq = w[t] = w[t] || [];
76  //     ttq.methods = ['page','track','identify','instances','debug','on','off','once','ready','alias','group','enableCookie','disableCookie'];
77  //     ttq.setAndDefer = function(obj, method){ obj[method] = function(){ obj.push([method].concat([].slice.call(arguments,0))) } };
78  //     for (var i=0;i<ttq.methods.length;i++) ttq.setAndDefer(ttq, ttq.methods[i]);
79  //     ttq.load = function(id, opts){ var u='https://analytics.tiktok.com/i18n/pixel/events.js';
80  //       ttq._i = ttq._i || {}; ttq._i[id] = []; ttq._i[id]._u = u; ttq._t = ttq._t || {}; ttq._t[id] = +new Date; ttq._o = ttq._o || {}; ttq._o[id] = opts || {};
81  //       var s = d.createElement('script'); s.type='text/javascript'; s.async=true; s.src = u+'?sdkid='+id+'&lib='+t;
82  //       var n = d.getElementsByTagName('script')[0]; n.parentNode.insertBefore(s,n);
83  //     };
84  //     ttq.load(C.tiktok);
85  //     if (ttAutoPage) ttq.page(); // só se flag ligada
86  //   })(window, document, 'ttq');
87  // }
88
89  // -----------------------------
90  // Hotjar
91  // -----------------------------
92  if (C.hotjar && C.hotjar.hjid) {
93    (function(h,o,t,j,a,r){
94      h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
95      h._hjSettings={hjid:C.hotjar.hjid,hjsv:C.hotjar.hjsv||6};
96      a=o.getElementsByTagName('head')[0];
97      r=o.createElement('script'); r.async=1;
98      r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
99      a.appendChild(r);
100    })(w,d,'https://static.hotjar.com/c/hotjar-','.js?sv=');
101  }
102
103  // -----------------------------
104  // Microsoft Bing UET
105  // -----------------------------
106  if (C.bing_uet) {
107    (function(w,d,t,r,u){var f,n,i;w[u]=w[u]||[],f=function(){
108      var o={ti:C.bing_uet, enableAutoSpaTracking: true}; o.q=w[u], w[u]=new UET(o), w[u].push("pageLoad");
109    };
110    n=d.createElement(t), n.src=r, n.async=1,
111    n.onload=n.onreadystatechange=function(){var s=this.readyState; s&&s!=="loaded"&&s!=="complete"||(f(),n.onload=n.onreadystatechange=null)};
112    i=d.getElementsByTagName(t)[0], i.parentNode.insertBefore(n,i)})(w,d,"script","//bat.bing.com/bat.js","uetq");
113
114    w.uet_report_conversion = function(vlr){
115      w.uetq = w.uetq || [];
116      w.uetq.push('event','purchase', { revenue_value: Number(vlr)||0, currency: 'BRL' });
117    };
118  }
119
120  // -----------------------------
121  // Clarity
122  // -----------------------------
123//   if (C.clarity) {
124//     (function(c,l,a,r,i,t,y){ c[a]=c[a]||function(){ (c[a].q=c[a].q||[]).push(arguments) };
125//       t=l.createElement(r); t.async=1; t.src="https://www.clarity.ms/tag/"+C.clarity;
126//       y=l.getElementsByTagName(r)[0]; y.parentNode.insertBefore(t,y);
127//     })(w, d, "clarity", "script");
128//   }
129
130  // -----------------------------
131  // Navegg
132  // -----------------------------
133  if (C.navegg_acc) {
134    (function(n,v,g){o="Navegg";if(!n[o]){a=v.createElement('script');a.src=g;b=document.getElementsByTagName('script')[0];
135    b.parentNode.insertBefore(a,b);n[o]=n[o]||function(parms){n[o].q=n[o].q||[];n[o].q.push([this, parms])};}})
136    (w, d, 'https://tag.navdmp.com/universal.min.js');
137    w.naveggReady = w.naveggReady || [];
138    w['nvg'+C.navegg_acc] = new w.Navegg({ acc: Number(C.navegg_acc) });
139  }
140
141  // -----------------------------
142  // API simples para SPA: chame em cada troca de rota
143  // -----------------------------
144  // Normaliza page_location: apenas pathname + ordenacao e pagina (se houver), em ordem fixa
145  function normalizePageLocation(href) {
146    try {
147      var u = new URL(href, w.location.origin);
148      var params = u.searchParams;
149      var ordenacao = params.get('ordenacao');
150      var pagina = params.get('pagina');
151      var parts = [];
152      if (ordenacao != null && ordenacao !== '') parts.push('ordenacao=' + encodeURIComponent(ordenacao));
153      if (pagina != null && pagina !== '') parts.push('pagina=' + encodeURIComponent(pagina));
154      var query = parts.length ? '?' + parts.join('&') : '';
155      return u.origin + u.pathname + query;
156    } catch (e) {
157      return href;
158    }
159  }
160
161  w.Analytics = w.Analytics || {};
162  
163  w.Analytics.page = function page(url) {
164  var loc = url || w.location.href;
165  var shouldSendPageView = true;
166  try {
167    var u = new URL(loc, w.location.origin);
168    var params = u.searchParams;
169    var ordenacao = params.get('ordenacao');
170    var pagina = params.get('pagina');
171    var hasOrdenacao = ordenacao != null && ordenacao !== '';
172    var hasPagina = pagina != null && pagina !== '';
173    // Regra: "par ou nenhum". Se só um existir, não dispara page_view.
174    shouldSendPageView = (hasOrdenacao && hasPagina) || (!hasOrdenacao && !hasPagina);
175  } catch (e) {
176    shouldSendPageView = true;
177  }
178  if (!shouldSendPageView) return;
179  var pageLocation = normalizePageLocation(loc);
180
181  // Cliente (GTM): recebe via dataLayer.
182  pushToClientDataLayer('page_view', { page_location: pageLocation });
183  // GA4 (Retailon + fallback cliente sem GTM): recebe via gtag + send_to.
184  sendToGA4('page_view', { page_location: pageLocation });
185  if (w.fbq  && C.fb_pixel && !metaAutoPV) trackFbq('track', 'PageView');
186  //if (w.ttq  && C.tiktok && !C.tiktokAutoPage) ttq.page();
187
188  // Sempre local (ok com ou sem GTM)
189  if (w.uetq) w.uetq.push('event', 'page_view');
190  if (w.hj) hj('stateChange', loc);
191  if (w.clarity) clarity('set', 'page', loc);
192};
193
194})(window, document);
195
196const EVENT_MAP = {
197  // descoberta / listas
198  ViewItemList:       { ga4: 'view_item_list', meta: 'ViewItemList_retailon' },
199  SelectItem:         { ga4: 'select_item',    meta: 'SelectItem_retailon'   },
200
201  // PDP / carrinho / checkout
202  ViewContent:        { ga4: 'view_item',      meta: 'ViewContent',              tiktok: 'ViewContent' },
203  AddToCart:          { ga4: 'add_to_cart',    meta: 'AddToCart_retailon',       tiktok: 'AddToCart'   }, // sensível
204  RemoveFromCart:     { ga4: 'remove_from_cart', meta: 'RemoveFromCart_retailon', tiktok: 'RemoveFromCart' },
205  ViewCart:           { ga4: 'view_cart',      meta: 'ViewCart_retailon' },
206  CloseCart:          { ga4: 'close_cart',     meta: 'CloseCart_retailon' },
207  InitiateCheckout:   { ga4: 'begin_checkout', meta: 'InitiateCheckout_retailon', tiktok: 'InitiateCheckout' }, // sensível
208  AddShippingInfo:    { ga4: 'add_shipping_info', meta: 'AddShippingInfo_retailon', tiktok: 'AddShippingInfo' },
209  AddPaymentInfo:     { ga4: 'add_payment_info', meta: 'AddPaymentInfo_retailon',  tiktok: 'AddPaymentInfo'  }, // sensível
210  Purchase:           { ga4: 'purchase',       meta: 'Purchase_retailon',        tiktok: 'CompletePayment' }, // sensível
211
212  // aquisição / utilitários
213  GenerateLead:       { ga4: 'generate_lead',  meta: 'Lead' }, // Meta padrão
214  CompleteRegistration:{ ga4: 'sign_up',       meta: 'CompleteRegistration', tiktok: 'CompleteRegistration' },
215  Login:              { ga4: 'login',          meta: 'Login_retailon',      tiktok: 'Login' },
216  Search:             { ga4: 'search',         meta: 'Search',              tiktok: 'Search' },
217  MenuAndCallToAction:{ ga4: 'select_content', meta: 'SelectContent_retailon' },
218  RequestContact:     { ga4: 'request_contact', meta: 'FindLocation' } // Meta: evento padrão de localização
219};
220
221function trackFbq() {
222  try {
223    if (typeof window.fbq === 'function') window.fbq.apply(window, arguments);
224  } catch (_err) { /* no-op */ }
225}
226
227// ========= helpers =========
228const num = v => {
229  const s = String(v ?? '').trim();
230  return s.includes(',') ? +s.replace(/\./g,'').replace(',', '.') : +s;
231};
232const qty = v => Math.max(1, parseInt(v || 1, 10));
233const MENU_EVENT_DEDUPE_MS = 500;
234
235// Evita "fbq is not defined" quando não há chave Meta
236// ou quando o arquivo do Meta é bloqueado por extensão.
237function ensureFbqNoop() {
238  if (typeof window.fbq === 'function') return;
239  const noop = function () {};
240  noop.loaded = false;
241  noop.version = '2.0-noop';
242  window.fbq = noop;
243}
244ensureFbqNoop();
245
246function shouldDedupeMenuEvent(termo) {
247  const key = [
248    termo?.event || '',
249    termo?.content_id != null ? String(termo.content_id) : '',
250    termo?.section || '',
251    termo?.position != null ? String(termo.position) : ''
252  ].join('|');
253  if (!key.replace(/\|/g, '')) return false;
254
255  const now = Date.now();
256  window.__AN_MENU_EVT_CACHE = window.__AN_MENU_EVT_CACHE || {};
257  const lastTs = window.__AN_MENU_EVT_CACHE[key];
258  window.__AN_MENU_EVT_CACHE[key] = now;
259
260  // limpeza simples para evitar crescimento sem limite da cache
261  const keys = Object.keys(window.__AN_MENU_EVT_CACHE);
262  if (keys.length > 200) {
263    const cutoff = now - (MENU_EVENT_DEDUPE_MS * 4);
264    keys.forEach((k) => {
265      if (window.__AN_MENU_EVT_CACHE[k] < cutoff) delete window.__AN_MENU_EVT_CACHE[k];
266    });
267  }
268
269  return typeof lastTs === 'number' && (now - lastTs) < MENU_EVENT_DEDUPE_MS;
270}
271
272function normalizeLeadPayload(termo) {
273  if (typeof termo === 'string') return { lead_type: termo };
274  if (!termo || typeof termo !== 'object' || Array.isArray(termo)) return {};
275
276  const leadPayload = {};
277  Object.keys(termo).forEach((k) => {
278    if (termo[k] !== undefined) leadPayload[k] = termo[k];
279  });
280  return leadPayload;
281}
282
283const mapGaItems = (arr=[]) => arr.map(i => {
284  const out = {
285    item_id: i.id,
286    item_name: i.item_name,
287    price: i.price,
288    quantity: qty(i.quantidade),
289    index: i.index || 1,
290    discount: i.discount,
291    brand: i.brand,
292    category: i.category,
293  };
294  if (i.item_list_name != null) out.item_list_name = i.item_list_name;
295  if (i.item_list_id != null) out.item_list_id = i.item_list_id;
296  return out;
297});
298
299const mapFbContents = (arr = []) => arr.map(i => ({
300  id: String(i.id),
301  quantity: Math.max(1, parseInt(i.quantidade || 1, 10)),
302  item_price: num(i.price)
303}));
304
305const mapTtContents = (arr = []) => arr.map(i => ({
306  content_id: String(i.id),
307  quantity: Math.max(1, parseInt(i.quantidade || 1, 10)),
308  price: num(i.price)
309}));
310
311// ========= destino GA4/GTM =========
312function hasGTM() {
313  return !!window.__AN_CFG?.gtm;
314}
315
316function hasRetailonGA4() {
317  return !!window.__AN_CFG?.ga4_retailon;
318}
319
320function hasClientGA4() {
321  return !!window.__AN_CFG?.ga4;
322}
323
324function getGA4Destinations() {
325  const destinations = [];
326  if (!hasGTM() && hasRetailonGA4()) destinations.push(window.__AN_CFG.ga4_retailon);
327  if (!hasGTM() && hasClientGA4()) destinations.push(window.__AN_CFG.ga4);
328  return destinations;
329}
330
331const ECOMMERCE_EVENTS = new Set([
332  'view_item_list',
333  'select_item',
334  'view_item',
335  'add_to_cart',
336  'remove_from_cart',
337  'view_cart',
338  'begin_checkout',
339  'add_shipping_info',
340  'add_payment_info',
341  'purchase'
342]);
343
344function buildEcommerceObject(params = {}) {
345  const ecommerce = {};
346  const keys = [
347    'currency',
348    'value',
349    'items',
350    'transaction_id',
351    'shipping',
352    'tax',
353    'coupon',
354    'affiliation',
355    'payment_type',
356    'shipping_tier'
357  ];
358  keys.forEach((k) => {
359    if (params[k] !== undefined) ecommerce[k] = params[k];
360  });
361  return ecommerce;
362}
363
364function pushToClientDataLayer(eventName, params = {}) {
365  if (!hasGTM() || !Array.isArray(window.dataLayer)) return;
366  const isEcommerceEvent = ECOMMERCE_EVENTS.has(eventName);
367
368  // Evita reaproveitamento de ecommerce/items de eventos anteriores no data model do GTM.
369  if (isEcommerceEvent) {
370    window.dataLayer.push({ ecommerce: null });
371  }
372
373  const payload = { event: eventName, ...params };
374  if (isEcommerceEvent) {
375    payload.ecommerce = buildEcommerceObject(params);
376    delete payload.currency;
377    delete payload.value;
378    delete payload.items;
379    delete payload.transaction_id;
380    delete payload.shipping;
381    delete payload.tax;
382    delete payload.coupon;
383    delete payload.affiliation;
384    delete payload.payment_type;
385    delete payload.shipping_tier;
386  }
387
388  window.dataLayer.push(payload);
389}
390
391function sendToGA4(eventName, params = {}) {
392  if (typeof window.gtag !== 'function') return;
393
394  // Com GTM ativo, eventos de GA4 devem ser roteados somente pelo container.
395  if (hasGTM()) {
396    return;
397  }
398
399  // fallback sem GTM
400  const destinations = getGA4Destinations();
401  if (!destinations.length) return;
402
403  window.gtag('event', eventName, { ...params, send_to: destinations });
404}
405
406function trackAnalyticsEvent(eventName, payload) {
407  if (!eventName) return;
408  pushToClientDataLayer(eventName, payload);
409  sendToGA4(eventName, payload);
410}
411
412// ========= despachante genérico =========
413function filtroParaDadosAnaliticos(referencia, termo) {
414  const cfg = EVENT_MAP[referencia];
415  if (!cfg) return;
416  if (referencia === 'MenuAndCallToAction' && shouldDedupeMenuEvent(termo)) return;
417  const hasMetaConfigured = !!window.__AN_CFG?.fb_pixel;
418
419  const currency = (termo && termo.currency) || 'BRL';
420
421  // Total do contexto do evento (número) 
422  // Ex.: no AddToCart, é o total desse clique de comprar; no Purchase, é o total pago (itens + frete − desconto).
423  const value    = termo && termo.value != null ? num(termo.value) : undefined; 
424
425  const items    = Array.isArray(termo?.items) ? termo.items : [];
426  const gaItems  = items.length ? mapGaItems(items) : undefined;
427  const fbCont   = items.length ? mapFbContents(items) : undefined;
428  const ttCont   = items.length ? mapTtContents(items) : undefined;
429  const ttTopId  = ttCont && ttCont[0]?.content_id;
430
431  // ---- GA4 ----
432  if (cfg.ga4) {
433    const base = { currency };
434    if (value != null) base.value = value;
435
436    // campos extras que o GA4 entende, se chegarem
437    if (gaItems) base.items = gaItems;
438    if (termo?.transaction_id) base.transaction_id = termo.transaction_id;
439    if (termo?.shipping != null) base.shipping = num(termo.shipping);
440    if (termo?.affiliation) base.affiliation = termo.affiliation;
441    if (termo?.coupon) base.coupon = termo.coupon;
442    if (window.__AN_CFG?.tenant_name) base.tenant_name = window.__AN_CFG.tenant_name;
443    if (window.__AN_CFG?.tenant_id) base.tenant_id = window.__AN_CFG.tenant_id;
444    if (window.__AN_CFG?.tenant_segment) base.tenant_segment = window.__AN_CFG.tenant_segment;
445    if (window.__AN_CFG?.price_zone) base.price_zone = window.__AN_CFG.price_zone;
446
447    // mapeamentos especiais de GA4
448    if (referencia === 'Search')      {
449      const searchPayload = (typeof termo === 'string')
450        ? { search_term: termo }
451        : (termo || {});
452      const normalizedSearchType = searchPayload.search_type || 'product';
453      const searchEvent = {
454        search_term: searchPayload.search_term || '',
455        search_type: normalizedSearchType,
456        results_count: searchPayload.results_count != null ? Number(searchPayload.results_count) : undefined,
457        state: searchPayload.state,
458        is_24h: searchPayload.is_24h,
459        trigger: searchPayload.trigger
460      };
461      Object.keys(searchEvent).forEach((k) => searchEvent[k] === undefined && delete searchEvent[k]);
462      trackAnalyticsEvent('search', searchEvent);
463    } else if (referencia === 'GenerateLead') {
464      const leadPayload = normalizeLeadPayload(termo);
465      const leadEvent = { ...base, ...leadPayload };
466      Object.keys(leadEvent).forEach((k) => leadEvent[k] === undefined && delete leadEvent[k]);
467      trackAnalyticsEvent(cfg.ga4, leadEvent);
468    } else if (referencia === 'MenuAndCallToAction') {
469      const extra = {
470        event: termo?.event,                 // ex: 'click_banner' ou 'click_pill'
471        content_type: termo?.content_type,   // ex: 'banner_carrossel' ou 'filtro'
472        content_id: termo?.content_id        // ex: id, href, texto da pílula
473      };
474    
475      if (termo?.position != null) extra.position = termo.position; // posição no carrossel
476      if (termo?.section)          extra.section  = termo.section;  // ex: 'home'
477    
478      trackAnalyticsEvent(cfg.ga4, {  // cfg.ga4 aqui é 'select_content'
479        ...base,                   // currency, tenant_name, tenant_id, etc.
480        ...extra
481      });
482    } else if (referencia === 'SelectItem') {
483      const extra = {
484        event: termo?.event,
485      };
486      if (termo?.item_list_name) extra.item_list_name = termo.item_list_name;
487      if (termo?.item_list_id)   extra.item_list_id   = termo.item_list_id;
488    
489      trackAnalyticsEvent('select_item', { 
490        ...base,     // inclui currency, value, items, tenant_name, etc.
491        ...extra
492      });
493    } else if (referencia === 'ViewItemList') {
494      if (termo?.item_list_name) base.item_list_name = termo.item_list_name;
495      if (termo?.item_list_id)   base.item_list_id   = termo.item_list_id;
496      trackAnalyticsEvent(cfg.ga4, base);
497    } else if (['CompleteRegistration', 'Login'].includes(referencia)) {
498      const method = (typeof termo === 'string' ? termo : termo?.method) || 'site_credentials';
499      trackAnalyticsEvent(cfg.ga4, { method });
500    } else {
501      trackAnalyticsEvent(cfg.ga4, base);
502    }
503  }
504
505  // ---- Meta (FB) ----
506  if (hasMetaConfigured && typeof window.fbq === 'function' && cfg.meta) {
507    // quais nomes usar como 'track' (padrão) vs 'trackCustom'
508    const metaStandard = new Set(['ViewContent','Lead','CompleteRegistration','Search','FindLocation']);
509    const useStandard  = metaStandard.has(cfg.meta);
510
511    const base = {};
512    if (value != null) base.value = value;
513    if (currency) base.currency = currency;
514    if (fbCont && fbCont.length) { base.content_type = 'product'; base.contents = fbCont; }
515
516    if (referencia === 'Search') {
517      const searchPayload = (typeof termo === 'string')
518        ? { search_term: termo }
519        : (termo || {});
520      const normalizedSearchType = searchPayload.search_type || 'product';
521      base.search_string = searchPayload.search_term || '';
522      base.search_type = normalizedSearchType;
523      if (searchPayload.results_count != null) base.results_count = Number(searchPayload.results_count);
524      if (searchPayload.state) base.state = searchPayload.state;
525      if (searchPayload.is_24h != null) base.is_24h = !!searchPayload.is_24h;
526      if (searchPayload.trigger) base.trigger = searchPayload.trigger;
527    }
528    if (referencia === 'GenerateLead') {
529      const leadPayload = normalizeLeadPayload(termo);
530      Object.assign(base, leadPayload);
531    }
532    if (referencia === 'MenuAndCallToAction') {
533      if (termo?.content_type) base.content_type = termo.content_type;
534      if (termo?.content_id) base.content_id = String(termo.content_id);
535      if (termo?.section) base.section = termo.section;
536      if (termo?.position != null) base.position = termo.position;
537      if (termo?.event) base.menu_event = termo.event;
538    }
539
540    if (useStandard) trackFbq('track', cfg.meta, base);
541    else trackFbq('trackCustom', cfg.meta, base);
542  }
543
544  // ---- DataLayer (GTM) para Meta/Facebook ----
545  try {
546    if (hasGTM() && Array.isArray(window.dataLayer) && cfg?.meta) {
547      const dlEvent = {
548        event: `fb_${cfg.meta || referencia}`.toLowerCase(), // ex: fb_viewcontent
549        event_source: 'site',
550        event_name: cfg.meta || referencia,
551        reference: referencia,
552        currency,
553        value: value != null ? value : undefined,
554        contents: fbCont,
555        content_ids: fbCont?.map(c => c.id),
556        content_type: fbCont?.length ? 'product' : undefined,
557      };
558      if (referencia === 'Search') {
559        const searchPayload = (typeof termo === 'string')
560          ? { search_term: termo }
561          : (termo || {});
562        const normalizedSearchType = searchPayload.search_type || 'product';
563        dlEvent.search_term = searchPayload.search_term || '';
564        dlEvent.search_type = normalizedSearchType;
565        dlEvent.results_count = searchPayload.results_count != null ? Number(searchPayload.results_count) : undefined;
566        dlEvent.state = searchPayload.state;
567        dlEvent.is_24h = searchPayload.is_24h;
568        dlEvent.trigger = searchPayload.trigger;
569      }
570      if (referencia === 'GenerateLead') {
571        const leadPayload = normalizeLeadPayload(termo);
572        Object.assign(dlEvent, leadPayload);
573      }
574      if (referencia === 'MenuAndCallToAction') {
575        dlEvent.content_type = termo?.content_type ?? dlEvent.content_type;
576        dlEvent.content_id = termo?.content_id != null ? String(termo.content_id) : undefined;
577        dlEvent.section = termo?.section;
578        dlEvent.position = termo?.position;
579        dlEvent.menu_event = termo?.event;
580      }
581
582      Object.keys(dlEvent).forEach((k) => dlEvent[k] === undefined && delete dlEvent[k]);
583      window.dataLayer.push(dlEvent);
584    }
585  } catch (_err) { /* no-op */ }
586
587  // ---- TikTok ----
588  // if (window.ttq && typeof ttq.track === 'function' && cfg.tiktok) {
589  //   const base = { content_type: 'product' };
590  //   if (ttTopId) base.content_id = ttTopId;
591  //   if (currency) base.currency = currency;
592  //   if (value != null) base.value = value;
593  //   if (ttCont && ttCont.length) base.contents = ttCont;
594  //   if (referencia === 'Search') base.query = (typeof termo === 'string' ? termo : termo?.search_term || '');
595  //   ttq.track(cfg.tiktok, base);
596  // }
597
598  // ---- SYNDI ----
599  if (referencia === 'AddToCart' && window.SYNDI) {
600    const first = gaItems?.[0];
601    window.SYNDI.push({
602      type: 'track',
603      event: 'addToCart',
604      qty: first?.quantity,
605      sku: first?.id,
606      price: value,
607      items: gaItems
608    });
609  }
610
611  if (referencia === 'Purchase' && typeof uet_report_conversion === 'function') {
612    const totalFb = num(termo.value) + num(termo.shipping);
613    uet_report_conversion(totalFb);
614  }
615}
616
617// --- Auto Pageview para SPA + dedupe por URL ---
618(function (w) {
619  function firePage(url) {
620    try {
621      const loc = url || w.location.href;
622      if (w.__AN_LAST_PV === loc) return;     // dedupe
623      w.__AN_LAST_PV = loc;
624      if (w.Analytics && typeof w.Analytics.page === 'function') {
625        w.Analytics.page(loc);
626      }
627    } catch (e) { /* no-op */ }
628  }
629
630  // 1) Primeiro pageview (carregamento inicial)
631  if (document.readyState === 'complete' || document.readyState === 'interactive') {
632    setTimeout(() => firePage(), 0);
633  } else {
634    w.addEventListener('DOMContentLoaded', () => firePage());
635  }
636
637  // 2) Navegação SPA via history API
638  ['pushState', 'replaceState'].forEach(fn => {
639    const orig = history[fn];
640    history[fn] = function () {
641      const ret = orig.apply(this, arguments);
642      w.dispatchEvent(new Event('spa:navigation'));
643      return ret;
644    };
645  });
646  w.addEventListener('spa:navigation', () => firePage());
647  w.addEventListener('popstate',        () => firePage());
648})(window);

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.